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 * 33 * Demuxes a .mov file into raw or compressed audio and/or video streams. 34 * 35 * This element supports both push and pull-based scheduling, depending on the 36 * capabilities of the upstream elements. 37 * 38 * <refsect2> 39 * <title>Example launch line</title> 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 * </refsect2> 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/tag/tag.h> 57 #include <gst/audio/audio.h> 58 #include <gst/video/video.h> 59 #include <gst/riff/riff.h> 60 #include <gst/pbutils/pbutils.h> 61 62 #include "qtatomparser.h" 63 #include "qtdemux_types.h" 64 #include "qtdemux_dump.h" 65 #include "fourcc.h" 66 #include "descriptors.h" 67 #include "qtdemux_lang.h" 68 #include "qtdemux.h" 69 #include "qtpalette.h" 70 71 #include <stdio.h> 72 #include <stdlib.h> 73 #include <string.h> 74 75 #include <math.h> 76 #include <gst/math-compat.h> 77 78 #ifdef HAVE_ZLIB 79 # include <zlib.h> 80 #endif 81 82 /* max. size considered 'sane' for non-mdat atoms */ 83 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024) 84 85 /* if the sample index is larger than this, something is likely wrong */ 86 #ifdef GSTREAMER_LITE 87 // relaxing the limitation since some long files has more than 50Mb sample index 88 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (500*1024*1024) 89 #else 90 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024) 91 #endif // GSTREAMER_LITE 92 93 /* For converting qt creation times to unix epoch times */ 94 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24) 95 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17 96 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \ 97 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY) 98 99 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4)) 100 101 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE) 102 103 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) ) 104 105 GST_DEBUG_CATEGORY (qtdemux_debug); 106 #define GST_CAT_DEFAULT qtdemux_debug 107 108 typedef struct _QtDemuxSegment QtDemuxSegment; 109 typedef struct _QtDemuxSample QtDemuxSample; 110 111 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo; 112 113 struct _QtDemuxSample 114 { 115 guint32 size; 116 gint32 pts_offset; /* Add this value to timestamp to get the pts */ 117 guint64 offset; 118 guint64 timestamp; /* DTS In mov time */ 119 guint32 duration; /* In mov time */ 120 gboolean keyframe; /* TRUE when this packet is a keyframe */ 121 }; 122 123 /* Macros for converting to/from timescale */ 124 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale)) 125 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND)) 126 127 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale)) 128 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND)) 129 130 /* timestamp is the DTS */ 131 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp)) 132 /* timestamp + offset + cslg_shift is the outgoing PTS */ 133 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset)) 134 /* timestamp + offset is the PTS used for internal seek calcuations */ 135 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset)) 136 /* timestamp + duration - dts is the duration */ 137 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts)) 138 139 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe) 140 141 /* 142 * Quicktime has tracks and segments. A track is a continuous piece of 143 * multimedia content. The track is not always played from start to finish but 144 * instead, pieces of the track are 'cut out' and played in sequence. This is 145 * what the segments do. 146 * 147 * Inside the track we have keyframes (K) and delta frames. The track has its 148 * own timing, which starts from 0 and extends to end. The position in the track 149 * is called the media_time. 150 * 151 * The segments now describe the pieces that should be played from this track 152 * and are basically tuples of media_time/duration/rate entries. We can have 153 * multiple segments and they are all played after one another. An example: 154 * 155 * segment 1: media_time: 1 second, duration: 1 second, rate 1 156 * segment 2: media_time: 3 second, duration: 2 second, rate 2 157 * 158 * To correctly play back this track, one must play: 1 second of media starting 159 * from media_time 1 followed by 2 seconds of media starting from media_time 3 160 * at a rate of 2. 161 * 162 * Each of the segments will be played at a specific time, the first segment at 163 * time 0, the second one after the duration of the first one, etc.. Note that 164 * the time in resulting playback is not identical to the media_time of the 165 * track anymore. 166 * 167 * Visually, assuming the track has 4 second of media_time: 168 * 169 * (a) (b) (c) (d) 170 * .-----------------------------------------------------------. 171 * track: | K.....K.........K........K.......K.......K...........K... | 172 * '-----------------------------------------------------------' 173 * 0 1 2 3 4 174 * .------------^ ^ .----------^ ^ 175 * / .-------------' / .------------------' 176 * / / .-----' / 177 * .--------------. .--------------. 178 * | segment 1 | | segment 2 | 179 * '--------------' '--------------' 180 * 181 * The challenge here is to cut out the right pieces of the track for each of 182 * the playback segments. This fortunately can easily be done with the SEGMENT 183 * events of GStreamer. 184 * 185 * For playback of segment 1, we need to provide the decoder with the keyframe 186 * (a), in the above figure, but we must instruct it only to output the decoded 187 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time 188 * position set to the time of the segment: 0. 189 * 190 * We then proceed to push data from keyframe (a) to frame (b). The decoder 191 * decodes but clips all before media_time 1. 192 * 193 * After finishing a segment, we push out a new SEGMENT event with the clipping 194 * boundaries of the new data. 195 * 196 * This is a good usecase for the GStreamer accumulated SEGMENT events. 197 */ 198 199 struct _QtDemuxSegment 200 { 201 /* global time and duration, all gst time */ 202 GstClockTime time; 203 GstClockTime stop_time; 204 GstClockTime duration; 205 /* media time of trak, all gst time */ 206 GstClockTime media_start; 207 GstClockTime media_stop; 208 gdouble rate; 209 /* Media start time in trak timescale units */ 210 guint32 trak_media_start; 211 }; 212 213 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE) 214 215 /* Used with fragmented MP4 files (mfra atom) */ 216 typedef struct 217 { 218 GstClockTime ts; 219 guint64 moof_offset; 220 } QtDemuxRandomAccessEntry; 221 222 typedef struct _QtDemuxStreamStsdEntry 223 { 224 GstCaps *caps; 225 guint32 fourcc; 226 gboolean sparse; 227 228 /* video info */ 229 gint width; 230 gint height; 231 gint par_w; 232 gint par_h; 233 /* Numerator/denominator framerate */ 234 gint fps_n; 235 gint fps_d; 236 GstVideoColorimetry colorimetry; 237 guint16 bits_per_sample; 238 guint16 color_table_id; 239 GstMemory *rgb8_palette; 240 guint interlace_mode; 241 guint field_order; 242 243 /* audio info */ 244 gdouble rate; 245 gint n_channels; 246 guint samples_per_packet; 247 guint samples_per_frame; 248 guint bytes_per_packet; 249 guint bytes_per_sample; 250 guint bytes_per_frame; 251 guint compression; 252 253 /* if we use chunks or samples */ 254 gboolean sampled; 255 guint padding; 256 257 } QtDemuxStreamStsdEntry; 258 259 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index])) 260 261 struct _QtDemuxStream 262 { 263 GstPad *pad; 264 265 QtDemuxStreamStsdEntry *stsd_entries; 266 guint stsd_entries_length; 267 guint cur_stsd_entry_index; 268 269 /* stream type */ 270 guint32 subtype; 271 272 gboolean new_caps; /* If TRUE, caps need to be generated (by 273 * calling _configure_stream()) This happens 274 * for MSS and fragmented streams */ 275 276 gboolean new_stream; /* signals that a stream_start is required */ 277 gboolean on_keyframe; /* if this stream last pushed buffer was a 278 * keyframe. This is important to identify 279 * where to stop pushing buffers after a 280 * segment stop time */ 281 282 /* if the stream has a redirect URI in its headers, we store it here */ 283 gchar *redirect_uri; 284 285 /* track id */ 286 guint track_id; 287 #ifdef GSTREAMER_LITE 288 gboolean track_enabled; 289 #endif // GSTREAMER_LITE 290 291 /* duration/scale */ 292 guint64 duration; /* in timescale units */ 293 guint32 timescale; 294 295 /* language */ 296 gchar lang_id[4]; /* ISO 639-2T language code */ 297 298 /* our samples */ 299 guint32 n_samples; 300 QtDemuxSample *samples; 301 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */ 302 guint32 first_duration; /* duration in timescale of first sample, used for figuring out 303 the framerate */ 304 guint32 n_samples_moof; /* sample count in a moof */ 305 guint64 duration_moof; /* duration in timescale of a moof, used for figure out 306 * the framerate of fragmented format stream */ 307 guint64 duration_last_moof; 308 309 guint32 offset_in_sample; /* Offset in the current sample, used for 310 * streams which have got exceedingly big 311 * sample size (such as 24s of raw audio). 312 * Only used when max_buffer_size is non-NULL */ 313 guint32 max_buffer_size; /* Maximum allowed size for output buffers. 314 * Currently only set for raw audio streams*/ 315 316 /* video info */ 317 /* aspect ratio */ 318 gint display_width; 319 gint display_height; 320 321 /* allocation */ 322 gboolean use_allocator; 323 GstAllocator *allocator; 324 GstAllocationParams params; 325 326 gsize alignment; 327 328 /* when a discontinuity is pending */ 329 gboolean discont; 330 331 /* list of buffers to push first */ 332 GSList *buffers; 333 334 /* if we need to clip this buffer. This is only needed for uncompressed 335 * data */ 336 gboolean need_clip; 337 338 /* buffer needs some custom processing, e.g. subtitles */ 339 gboolean need_process; 340 341 /* current position */ 342 guint32 segment_index; 343 guint32 sample_index; 344 GstClockTime time_position; /* in gst time */ 345 guint64 accumulated_base; 346 347 /* the Gst segment we are processing out, used for clipping */ 348 GstSegment segment; 349 350 /* quicktime segments */ 351 guint32 n_segments; 352 QtDemuxSegment *segments; 353 gboolean dummy_segment; 354 guint32 from_sample; 355 guint32 to_sample; 356 357 gboolean sent_eos; 358 GstTagList *stream_tags; 359 gboolean send_global_tags; 360 361 GstEvent *pending_event; 362 363 GstByteReader stco; 364 GstByteReader stsz; 365 GstByteReader stsc; 366 GstByteReader stts; 367 GstByteReader stss; 368 GstByteReader stps; 369 GstByteReader ctts; 370 371 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */ 372 gint64 stbl_index; 373 /* stco */ 374 guint co_size; 375 GstByteReader co_chunk; 376 guint32 first_chunk; 377 guint32 current_chunk; 378 guint32 last_chunk; 379 guint32 samples_per_chunk; 380 guint32 stsd_sample_description_id; 381 guint32 stco_sample_index; 382 /* stsz */ 383 guint32 sample_size; /* 0 means variable sizes are stored in stsz */ 384 /* stsc */ 385 guint32 stsc_index; 386 guint32 n_samples_per_chunk; 387 guint32 stsc_chunk_index; 388 guint32 stsc_sample_index; 389 guint64 chunk_offset; 390 /* stts */ 391 guint32 stts_index; 392 guint32 stts_samples; 393 guint32 n_sample_times; 394 guint32 stts_sample_index; 395 guint64 stts_time; 396 guint32 stts_duration; 397 /* stss */ 398 gboolean stss_present; 399 guint32 n_sample_syncs; 400 guint32 stss_index; 401 /* stps */ 402 gboolean stps_present; 403 guint32 n_sample_partial_syncs; 404 guint32 stps_index; 405 QtDemuxRandomAccessEntry *ra_entries; 406 guint n_ra_entries; 407 408 const QtDemuxRandomAccessEntry *pending_seek; 409 410 /* ctts */ 411 gboolean ctts_present; 412 guint32 n_composition_times; 413 guint32 ctts_index; 414 guint32 ctts_sample_index; 415 guint32 ctts_count; 416 gint32 ctts_soffset; 417 418 /* cslg */ 419 guint32 cslg_shift; 420 421 /* fragmented */ 422 gboolean parsed_trex; 423 guint32 def_sample_description_index; /* index is 1-based */ 424 guint32 def_sample_duration; 425 guint32 def_sample_size; 426 guint32 def_sample_flags; 427 428 gboolean disabled; 429 430 /* stereoscopic video streams */ 431 GstVideoMultiviewMode multiview_mode; 432 GstVideoMultiviewFlags multiview_flags; 433 434 /* protected streams */ 435 gboolean protected; 436 guint32 protection_scheme_type; 437 guint32 protection_scheme_version; 438 gpointer protection_scheme_info; /* specific to the protection scheme */ 439 GQueue protection_scheme_event_queue; 440 }; 441 442 /* Contains properties and cryptographic info for a set of samples from a 443 * track protected using Common Encryption (cenc) */ 444 struct _QtDemuxCencSampleSetInfo 445 { 446 GstStructure *default_properties; 447 448 /* @crypto_info holds one GstStructure per sample */ 449 GPtrArray *crypto_info; 450 }; 451 452 static const gchar * 453 qt_demux_state_string (enum QtDemuxState state) 454 { 455 switch (state) { 456 case QTDEMUX_STATE_INITIAL: 457 return "<INITIAL>"; 458 case QTDEMUX_STATE_HEADER: 459 return "<HEADER>"; 460 case QTDEMUX_STATE_MOVIE: 461 return "<MOVIE>"; 462 case QTDEMUX_STATE_BUFFER_MDAT: 463 return "<BUFFER_MDAT>"; 464 default: 465 return "<UNKNOWN>"; 466 } 467 } 468 469 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc); 470 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node, 471 guint32 fourcc, GstByteReader * parser); 472 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc); 473 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node, 474 guint32 fourcc, GstByteReader * parser); 475 476 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux); 477 478 static GstStaticPadTemplate gst_qtdemux_sink_template = 479 GST_STATIC_PAD_TEMPLATE ("sink", 480 GST_PAD_SINK, 481 GST_PAD_ALWAYS, 482 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; " 483 "application/x-3gp") 484 ); 485 486 static GstStaticPadTemplate gst_qtdemux_videosrc_template = 487 GST_STATIC_PAD_TEMPLATE ("video_%u", 488 GST_PAD_SRC, 489 GST_PAD_SOMETIMES, 490 GST_STATIC_CAPS_ANY); 491 492 static GstStaticPadTemplate gst_qtdemux_audiosrc_template = 493 GST_STATIC_PAD_TEMPLATE ("audio_%u", 494 GST_PAD_SRC, 495 GST_PAD_SOMETIMES, 496 GST_STATIC_CAPS_ANY); 497 498 static GstStaticPadTemplate gst_qtdemux_subsrc_template = 499 GST_STATIC_PAD_TEMPLATE ("subtitle_%u", 500 GST_PAD_SRC, 501 GST_PAD_SOMETIMES, 502 GST_STATIC_CAPS_ANY); 503 504 #define gst_qtdemux_parent_class parent_class 505 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT); 506 507 static void gst_qtdemux_dispose (GObject * object); 508 509 static guint32 510 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str, 511 GstClockTime media_time); 512 static guint32 513 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux, 514 QtDemuxStream * str, gint64 media_offset); 515 516 #if 0 517 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index); 518 static GstIndex *gst_qtdemux_get_index (GstElement * element); 519 #endif 520 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element, 521 GstStateChange transition); 522 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent); 523 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad, 524 GstObject * parent, GstPadMode mode, gboolean active); 525 526 static void gst_qtdemux_loop (GstPad * pad); 527 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, 528 GstBuffer * inbuf); 529 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent, 530 GstEvent * event); 531 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps); 532 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux, 533 QtDemuxStream * stream); 534 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux, 535 QtDemuxStream * stream); 536 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux, 537 gboolean force); 538 539 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux, 540 const guint8 * buffer, guint length); 541 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, 542 const guint8 * buffer, guint length); 543 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux); 544 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, 545 GNode * udta); 546 547 #ifdef GSTREAMER_LITE 548 static gboolean gst_qtdemux_handle_esds (GstQTDemux * qtdemux, 549 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds, 550 GstTagList * list); 551 #else 552 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux, 553 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds, 554 GstTagList * list); 555 #endif // GSTREAMER_LITE 556 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux, 557 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc, 558 const guint8 * stsd_entry_data, gchar ** codec_name); 559 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux, 560 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc, 561 const guint8 * data, int len, gchar ** codec_name); 562 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, 563 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data, 564 gchar ** codec_name); 565 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux, 566 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc, 567 const guint8 * stsd_entry_data, gchar ** codec_name); 568 569 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux, 570 QtDemuxStream * stream, guint32 n); 571 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux); 572 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux, 573 QtDemuxStream * stream); 574 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux, 575 QtDemuxStream * stream); 576 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index); 577 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux); 578 static void qtdemux_do_allocation (GstQTDemux * qtdemux, 579 QtDemuxStream * stream); 580 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux, 581 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset); 582 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, 583 QtDemuxStream * stream, gint seg_idx, GstClockTime offset, 584 GstClockTime * _start, GstClockTime * _stop); 585 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux, 586 QtDemuxStream * stream, gint segment_index, GstClockTime pos); 587 588 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux); 589 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration); 590 591 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes); 592 593 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux, 594 QtDemuxStream * stream, guint sample_index); 595 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux, 596 const gchar * id); 597 static void qtdemux_gst_structure_free (GstStructure * gststructure); 598 599 static void 600 gst_qtdemux_class_init (GstQTDemuxClass * klass) 601 { 602 GObjectClass *gobject_class; 603 GstElementClass *gstelement_class; 604 605 gobject_class = (GObjectClass *) klass; 606 gstelement_class = (GstElementClass *) klass; 607 608 parent_class = g_type_class_peek_parent (klass); 609 610 gobject_class->dispose = gst_qtdemux_dispose; 611 612 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state); 613 #if 0 614 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index); 615 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index); 616 #endif 617 618 gst_tag_register_musicbrainz_tags (); 619 620 gst_element_class_add_static_pad_template (gstelement_class, 621 &gst_qtdemux_sink_template); 622 gst_element_class_add_static_pad_template (gstelement_class, 623 &gst_qtdemux_videosrc_template); 624 gst_element_class_add_static_pad_template (gstelement_class, 625 &gst_qtdemux_audiosrc_template); 626 gst_element_class_add_static_pad_template (gstelement_class, 627 &gst_qtdemux_subsrc_template); 628 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer", 629 "Codec/Demuxer", 630 "Demultiplex a QuickTime file into audio and video streams", 631 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>"); 632 633 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin"); 634 gst_riff_init (); 635 } 636 637 static void 638 gst_qtdemux_init (GstQTDemux * qtdemux) 639 { 640 qtdemux->sinkpad = 641 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink"); 642 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate); 643 gst_pad_set_activatemode_function (qtdemux->sinkpad, 644 qtdemux_sink_activate_mode); 645 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain); 646 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event); 647 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad); 648 649 qtdemux->state = QTDEMUX_STATE_INITIAL; 650 qtdemux->pullbased = FALSE; 651 qtdemux->posted_redirect = FALSE; 652 qtdemux->neededbytes = 16; 653 qtdemux->todrop = 0; 654 qtdemux->adapter = gst_adapter_new (); 655 qtdemux->offset = 0; 656 qtdemux->first_mdat = -1; 657 qtdemux->got_moov = FALSE; 658 qtdemux->mdatoffset = -1; 659 qtdemux->mdatbuffer = NULL; 660 qtdemux->restoredata_buffer = NULL; 661 qtdemux->restoredata_offset = -1; 662 qtdemux->fragment_start = -1; 663 qtdemux->fragment_start_offset = -1; 664 qtdemux->media_caps = NULL; 665 qtdemux->exposed = FALSE; 666 qtdemux->mss_mode = FALSE; 667 qtdemux->pending_newsegment = NULL; 668 qtdemux->upstream_format_is_time = FALSE; 669 qtdemux->have_group_id = FALSE; 670 qtdemux->group_id = G_MAXUINT; 671 qtdemux->cenc_aux_info_offset = 0; 672 qtdemux->cenc_aux_info_sizes = NULL; 673 qtdemux->cenc_aux_sample_count = 0; 674 qtdemux->protection_system_ids = NULL; 675 g_queue_init (&qtdemux->protection_event_queue); 676 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME); 677 qtdemux->tag_list = gst_tag_list_new_empty (); 678 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL); 679 qtdemux->flowcombiner = gst_flow_combiner_new (); 680 681 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE); 682 } 683 684 static void 685 gst_qtdemux_dispose (GObject * object) 686 { 687 GstQTDemux *qtdemux = GST_QTDEMUX (object); 688 689 if (qtdemux->adapter) { 690 g_object_unref (G_OBJECT (qtdemux->adapter)); 691 qtdemux->adapter = NULL; 692 } 693 gst_tag_list_unref (qtdemux->tag_list); 694 gst_flow_combiner_free (qtdemux->flowcombiner); 695 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref, 696 NULL); 697 g_queue_clear (&qtdemux->protection_event_queue); 698 699 g_free (qtdemux->cenc_aux_info_sizes); 700 qtdemux->cenc_aux_info_sizes = NULL; 701 702 G_OBJECT_CLASS (parent_class)->dispose (object); 703 } 704 705 static void 706 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux) 707 { 708 if (qtdemux->posted_redirect) { 709 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX, 710 (_("This file contains no playable streams.")), 711 ("no known streams found, a redirect message has been posted")); 712 } else { 713 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX, 714 (_("This file contains no playable streams.")), 715 ("no known streams found")); 716 } 717 } 718 719 static GstBuffer * 720 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func) 721 { 722 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY, 723 mem, size, 0, size, mem, free_func); 724 } 725 726 static GstFlowReturn 727 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size, 728 GstBuffer ** buf) 729 { 730 GstFlowReturn flow; 731 GstMapInfo map; 732 gsize bsize; 733 734 if (G_UNLIKELY (size == 0)) { 735 GstFlowReturn ret; 736 GstBuffer *tmp = NULL; 737 738 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp); 739 if (ret != GST_FLOW_OK) 740 return ret; 741 742 gst_buffer_map (tmp, &map, GST_MAP_READ); 743 size = QT_UINT32 (map.data); 744 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size); 745 746 gst_buffer_unmap (tmp, &map); 747 gst_buffer_unref (tmp); 748 } 749 750 /* Sanity check: catch bogus sizes (fuzzed/broken files) */ 751 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) { 752 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) { 753 /* we're pulling header but already got most interesting bits, 754 * so never mind the rest (e.g. tags) (that much) */ 755 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT, 756 size); 757 return GST_FLOW_EOS; 758 } else { 759 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX, 760 (_("This file is invalid and cannot be played.")), 761 ("atom has bogus size %" G_GUINT64_FORMAT, size)); 762 return GST_FLOW_ERROR; 763 } 764 } 765 766 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf); 767 768 if (G_UNLIKELY (flow != GST_FLOW_OK)) 769 return flow; 770 771 bsize = gst_buffer_get_size (*buf); 772 /* Catch short reads - we don't want any partial atoms */ 773 if (G_UNLIKELY (bsize < size)) { 774 GST_WARNING_OBJECT (qtdemux, 775 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size); 776 gst_buffer_unref (*buf); 777 *buf = NULL; 778 return GST_FLOW_EOS; 779 } 780 781 return flow; 782 } 783 784 #if 1 785 static gboolean 786 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad, 787 GstFormat src_format, gint64 src_value, GstFormat dest_format, 788 gint64 * dest_value) 789 { 790 gboolean res = TRUE; 791 QtDemuxStream *stream = gst_pad_get_element_private (pad); 792 gint32 index; 793 794 if (stream->subtype != FOURCC_vide) { 795 res = FALSE; 796 goto done; 797 } 798 799 switch (src_format) { 800 case GST_FORMAT_TIME: 801 switch (dest_format) { 802 case GST_FORMAT_BYTES:{ 803 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value); 804 if (-1 == index) { 805 res = FALSE; 806 goto done; 807 } 808 809 *dest_value = stream->samples[index].offset; 810 811 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%" 812 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT, 813 GST_TIME_ARGS (src_value), *dest_value); 814 break; 815 } 816 default: 817 res = FALSE; 818 break; 819 } 820 break; 821 case GST_FORMAT_BYTES: 822 switch (dest_format) { 823 case GST_FORMAT_TIME:{ 824 index = 825 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux, 826 stream, src_value); 827 828 if (-1 == index) { 829 res = FALSE; 830 goto done; 831 } 832 833 *dest_value = 834 QTSTREAMTIME_TO_GSTTIME (stream, 835 stream->samples[index].timestamp); 836 GST_DEBUG_OBJECT (qtdemux, 837 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%" 838 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value)); 839 break; 840 } 841 default: 842 res = FALSE; 843 break; 844 } 845 break; 846 default: 847 res = FALSE; 848 break; 849 } 850 851 done: 852 return res; 853 } 854 #endif 855 856 static gboolean 857 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration) 858 { 859 gboolean res = FALSE; 860 861 *duration = GST_CLOCK_TIME_NONE; 862 863 if (qtdemux->duration != 0 && 864 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) { 865 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration); 866 res = TRUE; 867 } else { 868 *duration = GST_CLOCK_TIME_NONE; 869 } 870 871 return res; 872 } 873 874 static gboolean 875 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent, 876 GstQuery * query) 877 { 878 gboolean res = FALSE; 879 GstQTDemux *qtdemux = GST_QTDEMUX (parent); 880 881 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query)); 882 883 switch (GST_QUERY_TYPE (query)) { 884 case GST_QUERY_POSITION:{ 885 GstFormat fmt; 886 887 gst_query_parse_position (query, &fmt, NULL); 888 if (fmt == GST_FORMAT_TIME 889 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) { 890 gst_query_set_position (query, GST_FORMAT_TIME, 891 qtdemux->segment.position); 892 res = TRUE; 893 } 894 } 895 break; 896 case GST_QUERY_DURATION:{ 897 GstFormat fmt; 898 899 gst_query_parse_duration (query, &fmt, NULL); 900 if (fmt == GST_FORMAT_TIME) { 901 /* First try to query upstream */ 902 res = gst_pad_query_default (pad, parent, query); 903 if (!res) { 904 GstClockTime duration; 905 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) { 906 gst_query_set_duration (query, GST_FORMAT_TIME, duration); 907 res = TRUE; 908 } 909 } 910 } 911 break; 912 } 913 case GST_QUERY_CONVERT:{ 914 GstFormat src_fmt, dest_fmt; 915 gint64 src_value, dest_value = 0; 916 917 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL); 918 919 res = gst_qtdemux_src_convert (qtdemux, pad, 920 src_fmt, src_value, dest_fmt, &dest_value); 921 if (res) 922 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value); 923 924 break; 925 } 926 case GST_QUERY_FORMATS: 927 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES); 928 res = TRUE; 929 break; 930 case GST_QUERY_SEEKING:{ 931 GstFormat fmt; 932 gboolean seekable; 933 934 /* try upstream first */ 935 res = gst_pad_query_default (pad, parent, query); 936 937 if (!res) { 938 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL); 939 if (fmt == GST_FORMAT_TIME) { 940 GstClockTime duration; 941 942 gst_qtdemux_get_duration (qtdemux, &duration); 943 seekable = TRUE; 944 if (!qtdemux->pullbased) { 945 GstQuery *q; 946 947 /* we might be able with help from upstream */ 948 seekable = FALSE; 949 q = gst_query_new_seeking (GST_FORMAT_BYTES); 950 if (gst_pad_peer_query (qtdemux->sinkpad, q)) { 951 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL); 952 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable); 953 } 954 gst_query_unref (q); 955 } 956 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration); 957 res = TRUE; 958 } 959 } 960 break; 961 } 962 case GST_QUERY_SEGMENT: 963 { 964 GstFormat format; 965 gint64 start, stop; 966 967 format = qtdemux->segment.format; 968 969 start = 970 gst_segment_to_stream_time (&qtdemux->segment, format, 971 qtdemux->segment.start); 972 if ((stop = qtdemux->segment.stop) == -1) 973 stop = qtdemux->segment.duration; 974 else 975 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop); 976 977 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop); 978 res = TRUE; 979 break; 980 } 981 default: 982 res = gst_pad_query_default (pad, parent, query); 983 break; 984 } 985 986 #ifdef GSTREAMER_LITE 987 if (!res) 988 res = gst_pad_query_default (pad, parent, query); 989 #endif 990 991 return res; 992 } 993 994 static void 995 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream) 996 { 997 if (G_LIKELY (stream->pad)) { 998 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags", 999 GST_DEBUG_PAD_NAME (stream->pad)); 1000 1001 if (!gst_tag_list_is_empty (stream->stream_tags)) { 1002 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT, 1003 stream->stream_tags); 1004 gst_pad_push_event (stream->pad, 1005 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags))); 1006 } 1007 1008 if (G_UNLIKELY (stream->send_global_tags)) { 1009 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT, 1010 qtdemux->tag_list); 1011 gst_pad_push_event (stream->pad, 1012 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list))); 1013 stream->send_global_tags = FALSE; 1014 } 1015 } 1016 } 1017 1018 /* push event on all source pads; takes ownership of the event */ 1019 static void 1020 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event) 1021 { 1022 guint n; 1023 gboolean has_valid_stream = FALSE; 1024 GstEventType etype = GST_EVENT_TYPE (event); 1025 1026 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads", 1027 GST_EVENT_TYPE_NAME (event)); 1028 1029 for (n = 0; n < qtdemux->n_streams; n++) { 1030 GstPad *pad; 1031 QtDemuxStream *stream = qtdemux->streams[n]; 1032 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n); 1033 1034 if ((pad = stream->pad)) { 1035 has_valid_stream = TRUE; 1036 1037 if (etype == GST_EVENT_EOS) { 1038 /* let's not send twice */ 1039 if (stream->sent_eos) 1040 continue; 1041 stream->sent_eos = TRUE; 1042 } 1043 1044 gst_pad_push_event (pad, gst_event_ref (event)); 1045 } 1046 } 1047 1048 gst_event_unref (event); 1049 1050 /* if it is EOS and there are no pads, post an error */ 1051 if (!has_valid_stream && etype == GST_EVENT_EOS) { 1052 gst_qtdemux_post_no_playable_stream_error (qtdemux); 1053 } 1054 } 1055 1056 /* push a pending newsegment event, if any from the streaming thread */ 1057 static void 1058 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux) 1059 { 1060 if (qtdemux->pending_newsegment) { 1061 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment); 1062 qtdemux->pending_newsegment = NULL; 1063 } 1064 } 1065 1066 typedef struct 1067 { 1068 guint64 media_time; 1069 } FindData; 1070 1071 static gint 1072 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data) 1073 { 1074 if ((gint64) s1->timestamp + s1->pts_offset > *media_time) 1075 return 1; 1076 if ((gint64) s1->timestamp + s1->pts_offset == *media_time) 1077 return 0; 1078 1079 return -1; 1080 } 1081 1082 /* find the index of the sample that includes the data for @media_time using a 1083 * binary search. Only to be called in optimized cases of linear search below. 1084 * 1085 * Returns the index of the sample. 1086 */ 1087 static guint32 1088 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str, 1089 guint64 media_time) 1090 { 1091 QtDemuxSample *result; 1092 guint32 index; 1093 1094 /* convert media_time to mov format */ 1095 media_time = 1096 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND); 1097 1098 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1, 1099 sizeof (QtDemuxSample), (GCompareDataFunc) find_func, 1100 GST_SEARCH_MODE_BEFORE, &media_time, NULL); 1101 1102 if (G_LIKELY (result)) 1103 index = result - str->samples; 1104 else 1105 index = 0; 1106 1107 return index; 1108 } 1109 1110 1111 1112 /* find the index of the sample that includes the data for @media_offset using a 1113 * linear search 1114 * 1115 * Returns the index of the sample. 1116 */ 1117 static guint32 1118 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux, 1119 QtDemuxStream * str, gint64 media_offset) 1120 { 1121 QtDemuxSample *result = str->samples; 1122 guint32 index = 0; 1123 1124 if (result == NULL || str->n_samples == 0) 1125 return -1; 1126 1127 if (media_offset == result->offset) 1128 return index; 1129 1130 result++; 1131 while (index < str->n_samples - 1) { 1132 if (!qtdemux_parse_samples (qtdemux, str, index + 1)) 1133 goto parse_failed; 1134 1135 if (media_offset < result->offset) 1136 break; 1137 1138 index++; 1139 result++; 1140 } 1141 return index; 1142 1143 /* ERRORS */ 1144 parse_failed: 1145 { 1146 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1); 1147 return -1; 1148 } 1149 } 1150 1151 /* find the index of the sample that includes the data for @media_time using a 1152 * linear search, and keeping in mind that not all samples may have been parsed 1153 * yet. If possible, it will delegate to binary search. 1154 * 1155 * Returns the index of the sample. 1156 */ 1157 static guint32 1158 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str, 1159 GstClockTime media_time) 1160 { 1161 guint32 index = 0; 1162 guint64 mov_time; 1163 QtDemuxSample *sample; 1164 1165 /* convert media_time to mov format */ 1166 mov_time = 1167 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND); 1168 1169 sample = str->samples; 1170 if (mov_time == sample->timestamp + sample->pts_offset) 1171 return index; 1172 1173 /* use faster search if requested time in already parsed range */ 1174 sample = str->samples + str->stbl_index; 1175 if (str->stbl_index >= 0 && 1176 mov_time <= (sample->timestamp + sample->pts_offset)) 1177 return gst_qtdemux_find_index (qtdemux, str, media_time); 1178 1179 while (index < str->n_samples - 1) { 1180 if (!qtdemux_parse_samples (qtdemux, str, index + 1)) 1181 goto parse_failed; 1182 1183 sample = str->samples + index + 1; 1184 if (mov_time < (sample->timestamp + sample->pts_offset)) 1185 break; 1186 1187 index++; 1188 } 1189 return index; 1190 1191 /* ERRORS */ 1192 parse_failed: 1193 { 1194 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1); 1195 return -1; 1196 } 1197 } 1198 1199 /* find the index of the keyframe needed to decode the sample at @index 1200 * of stream @str, or of a subsequent keyframe (depending on @next) 1201 * 1202 * Returns the index of the keyframe. 1203 */ 1204 static guint32 1205 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str, 1206 guint32 index, gboolean next) 1207 { 1208 guint32 new_index = index; 1209 1210 if (index >= str->n_samples) { 1211 new_index = str->n_samples; 1212 goto beach; 1213 } 1214 1215 /* all keyframes, return index */ 1216 if (str->all_keyframe) { 1217 new_index = index; 1218 goto beach; 1219 } 1220 1221 /* else search until we have a keyframe */ 1222 while (new_index < str->n_samples) { 1223 if (next && !qtdemux_parse_samples (qtdemux, str, new_index)) 1224 goto parse_failed; 1225 1226 if (str->samples[new_index].keyframe) 1227 break; 1228 1229 if (new_index == 0) 1230 break; 1231 1232 if (next) 1233 new_index++; 1234 else 1235 new_index--; 1236 } 1237 1238 if (new_index == str->n_samples) { 1239 GST_DEBUG_OBJECT (qtdemux, "no next keyframe"); 1240 new_index = -1; 1241 } 1242 1243 beach: 1244 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u " 1245 "gave %u", next ? "after" : "before", index, new_index); 1246 1247 return new_index; 1248 1249 /* ERRORS */ 1250 parse_failed: 1251 { 1252 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index); 1253 return -1; 1254 } 1255 } 1256 1257 /* find the segment for @time_position for @stream 1258 * 1259 * Returns the index of the segment containing @time_position. 1260 * Returns the last segment and sets the @eos variable to TRUE 1261 * if the time is beyond the end. @eos may be NULL 1262 */ 1263 static guint32 1264 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream, 1265 GstClockTime time_position) 1266 { 1267 gint i; 1268 guint32 seg_idx; 1269 1270 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT, 1271 GST_TIME_ARGS (time_position)); 1272 1273 seg_idx = -1; 1274 for (i = 0; i < stream->n_segments; i++) { 1275 QtDemuxSegment *segment = &stream->segments[i]; 1276 1277 GST_LOG_OBJECT (stream->pad, 1278 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT, 1279 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time)); 1280 1281 /* For the last segment we include stop_time in the last segment */ 1282 if (i < stream->n_segments - 1) { 1283 if (segment->time <= time_position && time_position < segment->stop_time) { 1284 GST_LOG_OBJECT (stream->pad, "segment %d matches", i); 1285 seg_idx = i; 1286 break; 1287 } 1288 } else { 1289 /* Last segment always matches */ 1290 seg_idx = i; 1291 break; 1292 } 1293 } 1294 return seg_idx; 1295 } 1296 1297 /* move the stream @str to the sample position @index. 1298 * 1299 * Updates @str->sample_index and marks discontinuity if needed. 1300 */ 1301 static void 1302 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str, 1303 guint32 index) 1304 { 1305 /* no change needed */ 1306 if (index == str->sample_index) 1307 return; 1308 1309 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index, 1310 str->n_samples); 1311 1312 /* position changed, we have a discont */ 1313 str->sample_index = index; 1314 str->offset_in_sample = 0; 1315 /* Each time we move in the stream we store the position where we are 1316 * starting from */ 1317 str->from_sample = index; 1318 str->discont = TRUE; 1319 } 1320 1321 static void 1322 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time, 1323 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset) 1324 { 1325 guint64 min_offset; 1326 gint64 min_byte_offset = -1; 1327 gint n; 1328 1329 min_offset = desired_time; 1330 1331 /* for each stream, find the index of the sample in the segment 1332 * and move back to the previous keyframe. */ 1333 for (n = 0; n < qtdemux->n_streams; n++) { 1334 QtDemuxStream *str; 1335 guint32 index, kindex; 1336 guint32 seg_idx; 1337 GstClockTime media_start; 1338 GstClockTime media_time; 1339 GstClockTime seg_time; 1340 QtDemuxSegment *seg; 1341 gboolean empty_segment = FALSE; 1342 1343 str = qtdemux->streams[n]; 1344 1345 if (CUR_STREAM (str)->sparse && !use_sparse) 1346 continue; 1347 1348 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time); 1349 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx); 1350 1351 /* get segment and time in the segment */ 1352 seg = &str->segments[seg_idx]; 1353 seg_time = (desired_time - seg->time) * seg->rate; 1354 1355 while (QTSEGMENT_IS_EMPTY (seg)) { 1356 seg_time = 0; 1357 empty_segment = TRUE; 1358 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one", 1359 seg_idx); 1360 seg_idx++; 1361 if (seg_idx == str->n_segments) 1362 break; 1363 seg = &str->segments[seg_idx]; 1364 } 1365 1366 if (seg_idx == str->n_segments) { 1367 /* FIXME track shouldn't have the last segment as empty, but if it 1368 * happens we better handle it */ 1369 continue; 1370 } 1371 1372 /* get the media time in the segment */ 1373 media_start = seg->media_start + seg_time; 1374 1375 /* get the index of the sample with media time */ 1376 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start); 1377 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u" 1378 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)", 1379 GST_TIME_ARGS (media_start), index, str->samples[index].offset, 1380 empty_segment); 1381 1382 /* shift to next frame if we are looking for next keyframe */ 1383 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start 1384 && index < str->stbl_index) 1385 index++; 1386 1387 if (!empty_segment) { 1388 /* find previous keyframe */ 1389 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next); 1390 1391 /* we will settle for one before if none found after */ 1392 if (next && kindex == -1) 1393 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE); 1394 1395 /* if the keyframe is at a different position, we need to update the 1396 * requested seek time */ 1397 if (index != kindex) { 1398 index = kindex; 1399 1400 /* get timestamp of keyframe */ 1401 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]); 1402 GST_DEBUG_OBJECT (qtdemux, 1403 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %" 1404 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time), 1405 str->samples[kindex].offset); 1406 1407 /* keyframes in the segment get a chance to change the 1408 * desired_offset. keyframes out of the segment are 1409 * ignored. */ 1410 if (media_time >= seg->media_start) { 1411 GstClockTime seg_time; 1412 1413 /* this keyframe is inside the segment, convert back to 1414 * segment time */ 1415 seg_time = (media_time - seg->media_start) + seg->time; 1416 if ((!next && (seg_time < min_offset)) || 1417 (next && (seg_time > min_offset))) 1418 min_offset = seg_time; 1419 } 1420 } 1421 } 1422 1423 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset) 1424 min_byte_offset = str->samples[index].offset; 1425 } 1426 1427 if (key_time) 1428 *key_time = min_offset; 1429 if (key_offset) 1430 *key_offset = min_byte_offset; 1431 } 1432 1433 static gboolean 1434 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format, 1435 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop) 1436 { 1437 gboolean res; 1438 1439 g_return_val_if_fail (format != NULL, FALSE); 1440 g_return_val_if_fail (cur != NULL, FALSE); 1441 g_return_val_if_fail (stop != NULL, FALSE); 1442 1443 if (*format == GST_FORMAT_TIME) 1444 return TRUE; 1445 1446 res = TRUE; 1447 if (cur_type != GST_SEEK_TYPE_NONE) 1448 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur); 1449 if (res && stop_type != GST_SEEK_TYPE_NONE) 1450 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop); 1451 1452 if (res) 1453 *format = GST_FORMAT_TIME; 1454 1455 return res; 1456 } 1457 1458 /* perform seek in push based mode: 1459 find BYTE position to move to based on time and delegate to upstream 1460 */ 1461 static gboolean 1462 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event) 1463 { 1464 gdouble rate; 1465 GstFormat format; 1466 GstSeekFlags flags; 1467 GstSeekType cur_type, stop_type; 1468 gint64 cur, stop, key_cur; 1469 gboolean res; 1470 gint64 byte_cur; 1471 gint64 original_stop; 1472 guint32 seqnum; 1473 #ifdef GSTREAMER_LITE 1474 GstEvent * new_event = NULL; 1475 #endif // GSTREAMER_LITE 1476 1477 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek"); 1478 1479 gst_event_parse_seek (event, &rate, &format, &flags, 1480 &cur_type, &cur, &stop_type, &stop); 1481 seqnum = gst_event_get_seqnum (event); 1482 1483 /* only forward streaming and seeking is possible */ 1484 if (rate <= 0) 1485 goto unsupported_seek; 1486 1487 /* convert to TIME if needed and possible */ 1488 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur, 1489 stop_type, &stop)) 1490 goto no_format; 1491 1492 /* Upstream seek in bytes will have undefined stop, but qtdemux stores 1493 * the original stop position to use when upstream pushes the new segment 1494 * for this seek */ 1495 original_stop = stop; 1496 stop = -1; 1497 1498 /* find reasonable corresponding BYTE position, 1499 * also try to mind about keyframes, since we can not go back a bit for them 1500 * later on */ 1501 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should 1502 * mostly just work, but let's not yet boldly go there ... */ 1503 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur); 1504 1505 if (byte_cur == -1) 1506 goto abort_seek; 1507 1508 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, " 1509 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur, 1510 stop); 1511 1512 GST_OBJECT_LOCK (qtdemux); 1513 qtdemux->seek_offset = byte_cur; 1514 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) { 1515 qtdemux->push_seek_start = cur; 1516 } else { 1517 qtdemux->push_seek_start = key_cur; 1518 } 1519 1520 if (stop_type == GST_SEEK_TYPE_NONE) { 1521 qtdemux->push_seek_stop = qtdemux->segment.stop; 1522 } else { 1523 qtdemux->push_seek_stop = original_stop; 1524 } 1525 GST_OBJECT_UNLOCK (qtdemux); 1526 1527 /* BYTE seek event */ 1528 #ifdef GSTREAMER_LITE 1529 new_event = gst_event_new_seek(rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur, 1530 stop_type, stop); 1531 gst_event_set_seqnum(new_event, seqnum); 1532 res = gst_pad_push_event(qtdemux->sinkpad, new_event); 1533 if (res) { 1534 gst_event_unref(event); 1535 } 1536 #else // GSTREAMER_LITE 1537 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur, 1538 stop_type, stop); 1539 gst_event_set_seqnum (event, seqnum); 1540 res = gst_pad_push_event (qtdemux->sinkpad, event); 1541 #endif // GSTREAMER_LITE 1542 1543 return res; 1544 1545 /* ERRORS */ 1546 abort_seek: 1547 { 1548 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, " 1549 "seek aborted."); 1550 return FALSE; 1551 } 1552 unsupported_seek: 1553 { 1554 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted."); 1555 return FALSE; 1556 } 1557 no_format: 1558 { 1559 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted."); 1560 return FALSE; 1561 } 1562 } 1563 1564 /* perform the seek. 1565 * 1566 * We set all segment_indexes in the streams to unknown and 1567 * adjust the time_position to the desired position. this is enough 1568 * to trigger a segment switch in the streaming thread to start 1569 * streaming from the desired position. 1570 * 1571 * Keyframe seeking is a little more complicated when dealing with 1572 * segments. Ideally we want to move to the previous keyframe in 1573 * the segment but there might not be a keyframe in the segment. In 1574 * fact, none of the segments could contain a keyframe. We take a 1575 * practical approach: seek to the previous keyframe in the segment, 1576 * if there is none, seek to the beginning of the segment. 1577 * 1578 * Called with STREAM_LOCK 1579 */ 1580 static gboolean 1581 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment, 1582 guint32 seqnum, GstSeekFlags flags) 1583 { 1584 gint64 desired_offset; 1585 gint n; 1586 1587 desired_offset = segment->position; 1588 1589 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT, 1590 GST_TIME_ARGS (desired_offset)); 1591 1592 /* may not have enough fragmented info to do this adjustment, 1593 * and we can't scan (and probably should not) at this time with 1594 * possibly flushing upstream */ 1595 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) { 1596 gint64 min_offset; 1597 gboolean next, before, after; 1598 1599 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE); 1600 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER); 1601 next = after && !before; 1602 if (segment->rate < 0) 1603 next = !next; 1604 1605 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset, 1606 NULL); 1607 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %" 1608 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset)); 1609 desired_offset = min_offset; 1610 } 1611 1612 /* and set all streams to the final position */ 1613 gst_flow_combiner_reset (qtdemux->flowcombiner); 1614 qtdemux->segment_seqnum = seqnum; 1615 for (n = 0; n < qtdemux->n_streams; n++) { 1616 QtDemuxStream *stream = qtdemux->streams[n]; 1617 1618 stream->time_position = desired_offset; 1619 stream->accumulated_base = 0; 1620 stream->sample_index = -1; 1621 stream->offset_in_sample = 0; 1622 stream->segment_index = -1; 1623 stream->sent_eos = FALSE; 1624 1625 if (segment->flags & GST_SEEK_FLAG_FLUSH) 1626 gst_segment_init (&stream->segment, GST_FORMAT_TIME); 1627 } 1628 segment->position = desired_offset; 1629 segment->time = desired_offset; 1630 if (segment->rate >= 0) { 1631 segment->start = desired_offset; 1632 1633 /* we stop at the end */ 1634 if (segment->stop == -1) 1635 segment->stop = segment->duration; 1636 } else { 1637 segment->stop = desired_offset; 1638 } 1639 1640 if (qtdemux->fragmented) 1641 qtdemux->fragmented_seek_pending = TRUE; 1642 1643 return TRUE; 1644 } 1645 1646 /* do a seek in pull based mode */ 1647 static gboolean 1648 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event) 1649 { 1650 gdouble rate; 1651 GstFormat format; 1652 GstSeekFlags flags; 1653 GstSeekType cur_type, stop_type; 1654 gint64 cur, stop; 1655 gboolean flush; 1656 gboolean update; 1657 GstSegment seeksegment; 1658 guint32 seqnum = GST_SEQNUM_INVALID; 1659 GstEvent *flush_event; 1660 gboolean ret; 1661 1662 if (event) { 1663 GST_DEBUG_OBJECT (qtdemux, "doing seek with event"); 1664 1665 gst_event_parse_seek (event, &rate, &format, &flags, 1666 &cur_type, &cur, &stop_type, &stop); 1667 seqnum = gst_event_get_seqnum (event); 1668 1669 /* we have to have a format as the segment format. Try to convert 1670 * if not. */ 1671 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur, 1672 stop_type, &stop)) 1673 goto no_format; 1674 1675 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format)); 1676 } else { 1677 GST_DEBUG_OBJECT (qtdemux, "doing seek without event"); 1678 flags = 0; 1679 } 1680 1681 flush = flags & GST_SEEK_FLAG_FLUSH; 1682 1683 /* stop streaming, either by flushing or by pausing the task */ 1684 if (flush) { 1685 flush_event = gst_event_new_flush_start (); 1686 if (seqnum != GST_SEQNUM_INVALID) 1687 gst_event_set_seqnum (flush_event, seqnum); 1688 /* unlock upstream pull_range */ 1689 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event)); 1690 /* make sure out loop function exits */ 1691 gst_qtdemux_push_event (qtdemux, flush_event); 1692 } else { 1693 /* non flushing seek, pause the task */ 1694 gst_pad_pause_task (qtdemux->sinkpad); 1695 } 1696 1697 /* wait for streaming to finish */ 1698 GST_PAD_STREAM_LOCK (qtdemux->sinkpad); 1699 1700 /* copy segment, we need this because we still need the old 1701 * segment when we close the current segment. */ 1702 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment)); 1703 1704 if (event) { 1705 /* configure the segment with the seek variables */ 1706 GST_DEBUG_OBJECT (qtdemux, "configuring seek"); 1707 if (!gst_segment_do_seek (&seeksegment, rate, format, flags, 1708 cur_type, cur, stop_type, stop, &update)) { 1709 ret = FALSE; 1710 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing"); 1711 } else { 1712 /* now do the seek */ 1713 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags); 1714 } 1715 } else { 1716 /* now do the seek */ 1717 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags); 1718 } 1719 1720 /* prepare for streaming again */ 1721 if (flush) { 1722 flush_event = gst_event_new_flush_stop (TRUE); 1723 if (seqnum != GST_SEQNUM_INVALID) 1724 gst_event_set_seqnum (flush_event, seqnum); 1725 1726 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event)); 1727 gst_qtdemux_push_event (qtdemux, flush_event); 1728 } 1729 1730 /* commit the new segment */ 1731 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment)); 1732 1733 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) { 1734 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux), 1735 qtdemux->segment.format, qtdemux->segment.position); 1736 if (seqnum != GST_SEQNUM_INVALID) 1737 gst_message_set_seqnum (msg, seqnum); 1738 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg); 1739 } 1740 1741 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */ 1742 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop, 1743 qtdemux->sinkpad, NULL); 1744 1745 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad); 1746 1747 return ret; 1748 1749 /* ERRORS */ 1750 no_format: 1751 { 1752 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted."); 1753 return FALSE; 1754 } 1755 } 1756 1757 static gboolean 1758 qtdemux_ensure_index (GstQTDemux * qtdemux) 1759 { 1760 guint i; 1761 1762 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams"); 1763 1764 /* Build complete index */ 1765 for (i = 0; i < qtdemux->n_streams; i++) { 1766 QtDemuxStream *stream = qtdemux->streams[i]; 1767 1768 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) 1769 goto parse_error; 1770 } 1771 return TRUE; 1772 1773 /* ERRORS */ 1774 parse_error: 1775 { 1776 GST_LOG_OBJECT (qtdemux, 1777 "Building complete index of stream %u for seeking failed!", i); 1778 return FALSE; 1779 } 1780 } 1781 1782 static gboolean 1783 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent, 1784 GstEvent * event) 1785 { 1786 gboolean res = TRUE; 1787 GstQTDemux *qtdemux = GST_QTDEMUX (parent); 1788 1789 switch (GST_EVENT_TYPE (event)) { 1790 case GST_EVENT_SEEK: 1791 { 1792 #ifndef GST_DISABLE_GST_DEBUG 1793 GstClockTime ts = gst_util_get_timestamp (); 1794 #endif 1795 guint32 seqnum = gst_event_get_seqnum (event); 1796 1797 if (seqnum == qtdemux->segment_seqnum) { 1798 GST_LOG_OBJECT (pad, 1799 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum); 1800 gst_event_unref (event); 1801 return TRUE; 1802 } 1803 1804 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) { 1805 /* seek should be handled by upstream, we might need to re-download fragments */ 1806 GST_DEBUG_OBJECT (qtdemux, 1807 "let upstream handle seek for fragmented playback"); 1808 goto upstream; 1809 } 1810 1811 /* Build complete index for seeking; 1812 * if not a fragmented file at least */ 1813 if (!qtdemux->fragmented) 1814 if (!qtdemux_ensure_index (qtdemux)) 1815 goto index_failed; 1816 #ifndef GST_DISABLE_GST_DEBUG 1817 ts = gst_util_get_timestamp () - ts; 1818 GST_INFO_OBJECT (qtdemux, 1819 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts)); 1820 #endif 1821 } 1822 if (qtdemux->pullbased) { 1823 res = gst_qtdemux_do_seek (qtdemux, pad, event); 1824 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) { 1825 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked"); 1826 res = TRUE; 1827 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams 1828 && !qtdemux->fragmented) { 1829 res = gst_qtdemux_do_push_seek (qtdemux, pad, event); 1830 } else { 1831 GST_DEBUG_OBJECT (qtdemux, 1832 "ignoring seek in push mode in current state"); 1833 res = FALSE; 1834 } 1835 gst_event_unref (event); 1836 break; 1837 default: 1838 upstream: 1839 res = gst_pad_event_default (pad, parent, event); 1840 break; 1841 } 1842 1843 done: 1844 return res; 1845 1846 /* ERRORS */ 1847 index_failed: 1848 { 1849 GST_ERROR_OBJECT (qtdemux, "Index failed"); 1850 gst_event_unref (event); 1851 res = FALSE; 1852 goto done; 1853 } 1854 } 1855 1856 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos. 1857 * 1858 * If @fw is false, the coding order is explored backwards. 1859 * 1860 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching 1861 * sample is found for that track. 1862 * 1863 * The stream and sample index of the sample with the minimum offset in the direction explored 1864 * (see @fw) is returned in the output parameters @_stream and @_index respectively. 1865 * 1866 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the 1867 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in 1868 * @_stream and @_index. */ 1869 static void 1870 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw, 1871 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time) 1872 { 1873 gint i, n, index; 1874 gint64 time, min_time; 1875 QtDemuxStream *stream; 1876 1877 min_time = -1; 1878 stream = NULL; 1879 index = -1; 1880 1881 for (n = 0; n < qtdemux->n_streams; ++n) { 1882 QtDemuxStream *str; 1883 gint inc; 1884 gboolean set_sample; 1885 1886 str = qtdemux->streams[n]; 1887 set_sample = !set; 1888 1889 if (fw) { 1890 i = 0; 1891 inc = 1; 1892 } else { 1893 i = str->n_samples - 1; 1894 inc = -1; 1895 } 1896 1897 for (; (i >= 0) && (i < str->n_samples); i += inc) { 1898 if (str->samples[i].size == 0) 1899 continue; 1900 1901 if (fw && (str->samples[i].offset < byte_pos)) 1902 continue; 1903 1904 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos)) 1905 continue; 1906 1907 /* move stream to first available sample */ 1908 if (set) { 1909 gst_qtdemux_move_stream (qtdemux, str, i); 1910 set_sample = TRUE; 1911 } 1912 1913 /* avoid index from sparse streams since they might be far away */ 1914 if (!CUR_STREAM (str)->sparse) { 1915 /* determine min/max time */ 1916 time = QTSAMPLE_PTS (str, &str->samples[i]); 1917 if (min_time == -1 || (!fw && time > min_time) || 1918 (fw && time < min_time)) { 1919 min_time = time; 1920 } 1921 1922 /* determine stream with leading sample, to get its position */ 1923 if (!stream || 1924 (fw && (str->samples[i].offset < stream->samples[index].offset)) || 1925 (!fw && (str->samples[i].offset > stream->samples[index].offset))) { 1926 stream = str; 1927 index = i; 1928 } 1929 } 1930 break; 1931 } 1932 1933 /* no sample for this stream, mark eos */ 1934 if (!set_sample) 1935 gst_qtdemux_move_stream (qtdemux, str, str->n_samples); 1936 } 1937 1938 if (_time) 1939 *_time = min_time; 1940 if (_stream) 1941 *_stream = stream; 1942 if (_index) 1943 *_index = index; 1944 } 1945 1946 static QtDemuxStream * 1947 _create_stream (void) 1948 { 1949 QtDemuxStream *stream; 1950 1951 stream = g_new0 (QtDemuxStream, 1); 1952 /* new streams always need a discont */ 1953 stream->discont = TRUE; 1954 /* we enable clipping for raw audio/video streams */ 1955 stream->need_clip = FALSE; 1956 stream->need_process = FALSE; 1957 stream->segment_index = -1; 1958 stream->time_position = 0; 1959 stream->sample_index = -1; 1960 stream->offset_in_sample = 0; 1961 stream->new_stream = TRUE; 1962 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE; 1963 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE; 1964 stream->protected = FALSE; 1965 stream->protection_scheme_type = 0; 1966 stream->protection_scheme_version = 0; 1967 stream->protection_scheme_info = NULL; 1968 stream->n_samples_moof = 0; 1969 stream->duration_moof = 0; 1970 stream->duration_last_moof = 0; 1971 stream->alignment = 1; 1972 stream->stream_tags = gst_tag_list_new_empty (); 1973 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM); 1974 g_queue_init (&stream->protection_scheme_event_queue); 1975 return stream; 1976 } 1977 1978 static gboolean 1979 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps) 1980 { 1981 GstStructure *structure; 1982 const gchar *variant; 1983 const GstCaps *mediacaps = NULL; 1984 1985 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps); 1986 1987 structure = gst_caps_get_structure (caps, 0); 1988 variant = gst_structure_get_string (structure, "variant"); 1989 1990 if (variant && strcmp (variant, "mss-fragmented") == 0) { 1991 QtDemuxStream *stream; 1992 const GValue *value; 1993 1994 demux->fragmented = TRUE; 1995 demux->mss_mode = TRUE; 1996 1997 if (demux->n_streams > 1) { 1998 /* can't do this, we can only renegotiate for another mss format */ 1999 return FALSE; 2000 } 2001 2002 value = gst_structure_get_value (structure, "media-caps"); 2003 /* create stream */ 2004 if (value) { 2005 const GValue *timescale_v; 2006 2007 /* TODO update when stream changes during playback */ 2008 2009 if (demux->n_streams == 0) { 2010 stream = _create_stream (); 2011 demux->streams[demux->n_streams] = stream; 2012 demux->n_streams = 1; 2013 /* mss has no stsd/stsd entry, use id 0 as default */ 2014 stream->stsd_entries_length = 1; 2015 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0; 2016 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1); 2017 } else { 2018 stream = demux->streams[0]; 2019 } 2020 2021 timescale_v = gst_structure_get_value (structure, "timescale"); 2022 if (timescale_v) { 2023 stream->timescale = g_value_get_uint64 (timescale_v); 2024 } else { 2025 /* default mss timescale */ 2026 stream->timescale = 10000000; 2027 } 2028 demux->timescale = stream->timescale; 2029 2030 mediacaps = gst_value_get_caps (value); 2031 if (!CUR_STREAM (stream)->caps 2032 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) { 2033 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT, 2034 mediacaps); 2035 stream->new_caps = TRUE; 2036 } 2037 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps); 2038 structure = gst_caps_get_structure (mediacaps, 0); 2039 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) { 2040 stream->subtype = FOURCC_vide; 2041 2042 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width); 2043 gst_structure_get_int (structure, "height", 2044 &CUR_STREAM (stream)->height); 2045 gst_structure_get_fraction (structure, "framerate", 2046 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d); 2047 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) { 2048 gint rate = 0; 2049 stream->subtype = FOURCC_soun; 2050 gst_structure_get_int (structure, "channels", 2051 &CUR_STREAM (stream)->n_channels); 2052 gst_structure_get_int (structure, "rate", &rate); 2053 CUR_STREAM (stream)->rate = rate; 2054 } 2055 } 2056 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps); 2057 } else { 2058 demux->mss_mode = FALSE; 2059 } 2060 2061 return TRUE; 2062 } 2063 2064 static void 2065 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard) 2066 { 2067 gint n; 2068 2069 GST_DEBUG_OBJECT (qtdemux, "Resetting demux"); 2070 gst_pad_stop_task (qtdemux->sinkpad); 2071 2072 if (hard || qtdemux->upstream_format_is_time) { 2073 qtdemux->state = QTDEMUX_STATE_INITIAL; 2074 qtdemux->neededbytes = 16; 2075 qtdemux->todrop = 0; 2076 qtdemux->pullbased = FALSE; 2077 qtdemux->posted_redirect = FALSE; 2078 qtdemux->first_mdat = -1; 2079 qtdemux->header_size = 0; 2080 qtdemux->mdatoffset = -1; 2081 qtdemux->restoredata_offset = -1; 2082 if (qtdemux->mdatbuffer) 2083 gst_buffer_unref (qtdemux->mdatbuffer); 2084 if (qtdemux->restoredata_buffer) 2085 gst_buffer_unref (qtdemux->restoredata_buffer); 2086 qtdemux->mdatbuffer = NULL; 2087 qtdemux->restoredata_buffer = NULL; 2088 qtdemux->mdatleft = 0; 2089 qtdemux->mdatsize = 0; 2090 if (qtdemux->comp_brands) 2091 gst_buffer_unref (qtdemux->comp_brands); 2092 qtdemux->comp_brands = NULL; 2093 qtdemux->last_moov_offset = -1; 2094 if (qtdemux->moov_node_compressed) { 2095 g_node_destroy (qtdemux->moov_node_compressed); 2096 if (qtdemux->moov_node) 2097 g_free (qtdemux->moov_node->data); 2098 } 2099 qtdemux->moov_node_compressed = NULL; 2100 if (qtdemux->moov_node) 2101 g_node_destroy (qtdemux->moov_node); 2102 qtdemux->moov_node = NULL; 2103 if (qtdemux->tag_list) 2104 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list)); 2105 qtdemux->tag_list = gst_tag_list_new_empty (); 2106 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL); 2107 #if 0 2108 if (qtdemux->element_index) 2109 gst_object_unref (qtdemux->element_index); 2110 qtdemux->element_index = NULL; 2111 #endif 2112 qtdemux->major_brand = 0; 2113 if (qtdemux->pending_newsegment) 2114 gst_event_unref (qtdemux->pending_newsegment); 2115 qtdemux->pending_newsegment = NULL; 2116 qtdemux->upstream_format_is_time = FALSE; 2117 qtdemux->upstream_seekable = FALSE; 2118 qtdemux->upstream_size = 0; 2119 2120 qtdemux->fragment_start = -1; 2121 qtdemux->fragment_start_offset = -1; 2122 qtdemux->duration = 0; 2123 qtdemux->moof_offset = 0; 2124 qtdemux->chapters_track_id = 0; 2125 qtdemux->have_group_id = FALSE; 2126 qtdemux->group_id = G_MAXUINT; 2127 2128 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref, 2129 NULL); 2130 g_queue_clear (&qtdemux->protection_event_queue); 2131 } 2132 qtdemux->offset = 0; 2133 gst_adapter_clear (qtdemux->adapter); 2134 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME); 2135 qtdemux->segment_seqnum = GST_SEQNUM_INVALID; 2136 2137 if (hard) { 2138 for (n = 0; n < qtdemux->n_streams; n++) { 2139 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]); 2140 qtdemux->streams[n] = NULL; 2141 } 2142 qtdemux->n_streams = 0; 2143 qtdemux->n_video_streams = 0; 2144 qtdemux->n_audio_streams = 0; 2145 qtdemux->n_sub_streams = 0; 2146 qtdemux->exposed = FALSE; 2147 qtdemux->fragmented = FALSE; 2148 qtdemux->mss_mode = FALSE; 2149 gst_caps_replace (&qtdemux->media_caps, NULL); 2150 qtdemux->timescale = 0; 2151 qtdemux->got_moov = FALSE; 2152 if (qtdemux->protection_system_ids) { 2153 g_ptr_array_free (qtdemux->protection_system_ids, TRUE); 2154 qtdemux->protection_system_ids = NULL; 2155 } 2156 } else if (qtdemux->mss_mode) { 2157 gst_flow_combiner_reset (qtdemux->flowcombiner); 2158 for (n = 0; n < qtdemux->n_streams; n++) 2159 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]); 2160 } else { 2161 gst_flow_combiner_reset (qtdemux->flowcombiner); 2162 for (n = 0; n < qtdemux->n_streams; n++) { 2163 qtdemux->streams[n]->sent_eos = FALSE; 2164 qtdemux->streams[n]->time_position = 0; 2165 qtdemux->streams[n]->accumulated_base = 0; 2166 } 2167 if (!qtdemux->pending_newsegment) { 2168 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment); 2169 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) 2170 gst_event_set_seqnum (qtdemux->pending_newsegment, 2171 qtdemux->segment_seqnum); 2172 } 2173 } 2174 } 2175 2176 2177 /* Maps the @segment to the qt edts internal segments and pushes 2178 * the correspnding segment event. 2179 * 2180 * If it ends up being at a empty segment, a gap will be pushed and the next 2181 * edts segment will be activated in sequence. 2182 * 2183 * To be used in push-mode only */ 2184 static void 2185 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment) 2186 { 2187 gint n, i; 2188 2189 for (n = 0; n < qtdemux->n_streams; n++) { 2190 QtDemuxStream *stream = qtdemux->streams[n]; 2191 2192 stream->time_position = segment->start; 2193 2194 /* in push mode we should be guaranteed that we will have empty segments 2195 * at the beginning and then one segment after, other scenarios are not 2196 * supported and are discarded when parsing the edts */ 2197 for (i = 0; i < stream->n_segments; i++) { 2198 if (stream->segments[i].stop_time > segment->start) { 2199 gst_qtdemux_activate_segment (qtdemux, stream, i, 2200 stream->time_position); 2201 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) { 2202 /* push the empty segment and move to the next one */ 2203 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i, 2204 stream->time_position); 2205 continue; 2206 } 2207 2208 g_assert (i == stream->n_segments - 1); 2209 } 2210 } 2211 } 2212 } 2213 2214 static gboolean 2215 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent, 2216 GstEvent * event) 2217 { 2218 GstQTDemux *demux = GST_QTDEMUX (parent); 2219 gboolean res = TRUE; 2220 2221 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event)); 2222 2223 switch (GST_EVENT_TYPE (event)) { 2224 case GST_EVENT_SEGMENT: 2225 { 2226 gint64 offset = 0; 2227 QtDemuxStream *stream; 2228 gint idx; 2229 GstSegment segment; 2230 2231 /* some debug output */ 2232 gst_event_copy_segment (event, &segment); 2233 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT, 2234 &segment); 2235 2236 /* erase any previously set segment */ 2237 gst_event_replace (&demux->pending_newsegment, NULL); 2238 2239 if (segment.format == GST_FORMAT_TIME) { 2240 GST_DEBUG_OBJECT (demux, "new pending_newsegment"); 2241 gst_event_replace (&demux->pending_newsegment, event); 2242 demux->upstream_format_is_time = TRUE; 2243 } else { 2244 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, " 2245 "not in time format"); 2246 2247 /* chain will send initial newsegment after pads have been added */ 2248 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) { 2249 GST_DEBUG_OBJECT (demux, "still starting, eating event"); 2250 goto exit; 2251 } 2252 } 2253 2254 /* check if this matches a time seek we received previously 2255 * FIXME for backwards compatibility reasons we use the 2256 * seek_offset here to compare. In the future we might want to 2257 * change this to use the seqnum as it uniquely should identify 2258 * the segment that corresponds to the seek. */ 2259 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT 2260 ", received segment offset %" G_GINT64_FORMAT, 2261 demux->seek_offset, segment.start); 2262 if (segment.format == GST_FORMAT_BYTES 2263 && demux->seek_offset == segment.start) { 2264 GST_OBJECT_LOCK (demux); 2265 offset = segment.start; 2266 2267 segment.format = GST_FORMAT_TIME; 2268 segment.start = demux->push_seek_start; 2269 segment.stop = demux->push_seek_stop; 2270 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek " 2271 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, 2272 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop)); 2273 GST_OBJECT_UNLOCK (demux); 2274 } 2275 2276 /* we only expect a BYTE segment, e.g. following a seek */ 2277 if (segment.format == GST_FORMAT_BYTES) { 2278 if (GST_CLOCK_TIME_IS_VALID (segment.start)) { 2279 offset = segment.start; 2280 2281 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL, 2282 NULL, (gint64 *) & segment.start); 2283 if ((gint64) segment.start < 0) 2284 segment.start = 0; 2285 } 2286 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) { 2287 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL, 2288 NULL, (gint64 *) & segment.stop); 2289 /* keyframe seeking should already arrange for start >= stop, 2290 * but make sure in other rare cases */ 2291 segment.stop = MAX (segment.stop, segment.start); 2292 } 2293 } else if (segment.format == GST_FORMAT_TIME) { 2294 /* push all data on the adapter before starting this 2295 * new segment */ 2296 gst_qtdemux_process_adapter (demux, TRUE); 2297 } else { 2298 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring"); 2299 goto exit; 2300 } 2301 2302 /* We shouldn't modify upstream driven TIME FORMAT segment */ 2303 if (!demux->upstream_format_is_time) { 2304 /* accept upstream's notion of segment and distribute along */ 2305 segment.format = GST_FORMAT_TIME; 2306 segment.position = segment.time = segment.start; 2307 segment.duration = demux->segment.duration; 2308 segment.base = gst_segment_to_running_time (&demux->segment, 2309 GST_FORMAT_TIME, demux->segment.position); 2310 } 2311 2312 gst_segment_copy_into (&segment, &demux->segment); 2313 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment); 2314 2315 /* map segment to internal qt segments and push on each stream */ 2316 if (demux->n_streams) { 2317 if (demux->fragmented) { 2318 GstEvent *segment_event = gst_event_new_segment (&segment); 2319 2320 gst_event_replace (&demux->pending_newsegment, NULL); 2321 gst_event_set_seqnum (segment_event, demux->segment_seqnum); 2322 gst_qtdemux_push_event (demux, segment_event); 2323 } else { 2324 gst_event_replace (&demux->pending_newsegment, NULL); 2325 gst_qtdemux_map_and_push_segments (demux, &segment); 2326 } 2327 } 2328 2329 /* clear leftover in current segment, if any */ 2330 gst_adapter_clear (demux->adapter); 2331 2332 /* set up streaming thread */ 2333 demux->offset = offset; 2334 if (demux->upstream_format_is_time) { 2335 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, " 2336 "set values to restart reading from a new atom"); 2337 demux->neededbytes = 16; 2338 demux->todrop = 0; 2339 } else { 2340 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, 2341 NULL); 2342 if (stream) { 2343 demux->todrop = stream->samples[idx].offset - offset; 2344 demux->neededbytes = demux->todrop + stream->samples[idx].size; 2345 } else { 2346 /* set up for EOS */ 2347 demux->neededbytes = -1; 2348 demux->todrop = 0; 2349 } 2350 } 2351 exit: 2352 gst_event_unref (event); 2353 res = TRUE; 2354 goto drop; 2355 } 2356 case GST_EVENT_FLUSH_START: 2357 { 2358 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) { 2359 gst_event_unref (event); 2360 goto drop; 2361 } 2362 break; 2363 } 2364 case GST_EVENT_FLUSH_STOP: 2365 { 2366 guint64 dur; 2367 2368 dur = demux->segment.duration; 2369 gst_qtdemux_reset (demux, FALSE); 2370 demux->segment.duration = dur; 2371 2372 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) { 2373 gst_event_unref (event); 2374 goto drop; 2375 } 2376 break; 2377 } 2378 case GST_EVENT_EOS: 2379 /* If we are in push mode, and get an EOS before we've seen any streams, 2380 * then error out - we have nowhere to send the EOS */ 2381 if (!demux->pullbased) { 2382 gint i; 2383 gboolean has_valid_stream = FALSE; 2384 for (i = 0; i < demux->n_streams; i++) { 2385 if (demux->streams[i]->pad != NULL) { 2386 has_valid_stream = TRUE; 2387 break; 2388 } 2389 } 2390 if (!has_valid_stream) 2391 gst_qtdemux_post_no_playable_stream_error (demux); 2392 else { 2393 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u", 2394 (guint) gst_adapter_available (demux->adapter)); 2395 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) { 2396 res = FALSE; 2397 } 2398 } 2399 } 2400 break; 2401 case GST_EVENT_CAPS:{ 2402 GstCaps *caps = NULL; 2403 2404 gst_event_parse_caps (event, &caps); 2405 gst_qtdemux_setcaps (demux, caps); 2406 res = TRUE; 2407 gst_event_unref (event); 2408 goto drop; 2409 } 2410 case GST_EVENT_PROTECTION: 2411 { 2412 const gchar *system_id = NULL; 2413 2414 gst_event_parse_protection (event, &system_id, NULL, NULL); 2415 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s", 2416 system_id); 2417 gst_qtdemux_append_protection_system_id (demux, system_id); 2418 /* save the event for later, for source pads that have not been created */ 2419 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event)); 2420 /* send it to all pads that already exist */ 2421 gst_qtdemux_push_event (demux, event); 2422 res = TRUE; 2423 goto drop; 2424 } 2425 default: 2426 break; 2427 } 2428 2429 res = gst_pad_event_default (demux->sinkpad, parent, event) & res; 2430 2431 drop: 2432 return res; 2433 } 2434 2435 #if 0 2436 static void 2437 gst_qtdemux_set_index (GstElement * element, GstIndex * index) 2438 { 2439 GstQTDemux *demux = GST_QTDEMUX (element); 2440 2441 GST_OBJECT_LOCK (demux); 2442 if (demux->element_index) 2443 gst_object_unref (demux->element_index); 2444 if (index) { 2445 demux->element_index = gst_object_ref (index); 2446 } else { 2447 demux->element_index = NULL; 2448 } 2449 GST_OBJECT_UNLOCK (demux); 2450 /* object lock might be taken again */ 2451 if (index) 2452 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id); 2453 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d", 2454 demux->element_index, demux->index_id); 2455 } 2456 2457 static GstIndex * 2458 gst_qtdemux_get_index (GstElement * element) 2459 { 2460 GstIndex *result = NULL; 2461 GstQTDemux *demux = GST_QTDEMUX (element); 2462 2463 GST_OBJECT_LOCK (demux); 2464 if (demux->element_index) 2465 result = gst_object_ref (demux->element_index); 2466 GST_OBJECT_UNLOCK (demux); 2467 2468 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result); 2469 2470 return result; 2471 } 2472 #endif 2473 2474 static void 2475 gst_qtdemux_stbl_free (QtDemuxStream * stream) 2476 { 2477 g_free ((gpointer) stream->stco.data); 2478 stream->stco.data = NULL; 2479 g_free ((gpointer) stream->stsz.data); 2480 stream->stsz.data = NULL; 2481 g_free ((gpointer) stream->stsc.data); 2482 stream->stsc.data = NULL; 2483 g_free ((gpointer) stream->stts.data); 2484 stream->stts.data = NULL; 2485 g_free ((gpointer) stream->stss.data); 2486 stream->stss.data = NULL; 2487 g_free ((gpointer) stream->stps.data); 2488 stream->stps.data = NULL; 2489 g_free ((gpointer) stream->ctts.data); 2490 stream->ctts.data = NULL; 2491 } 2492 2493 static void 2494 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux, 2495 QtDemuxStream * stream) 2496 { 2497 g_free (stream->segments); 2498 stream->segments = NULL; 2499 stream->segment_index = -1; 2500 stream->accumulated_base = 0; 2501 } 2502 2503 static void 2504 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux, 2505 QtDemuxStream * stream) 2506 { 2507 g_free (stream->samples); 2508 stream->samples = NULL; 2509 gst_qtdemux_stbl_free (stream); 2510 2511 /* fragments */ 2512 g_free (stream->ra_entries); 2513 stream->ra_entries = NULL; 2514 stream->n_ra_entries = 0; 2515 2516 stream->sample_index = -1; 2517 stream->stbl_index = -1; 2518 stream->n_samples = 0; 2519 stream->time_position = 0; 2520 2521 stream->n_samples_moof = 0; 2522 stream->duration_moof = 0; 2523 stream->duration_last_moof = 0; 2524 } 2525 2526 static void 2527 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream) 2528 { 2529 gint i; 2530 if (stream->allocator) 2531 gst_object_unref (stream->allocator); 2532 while (stream->buffers) { 2533 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data)); 2534 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers); 2535 } 2536 for (i = 0; i < stream->stsd_entries_length; i++) { 2537 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i]; 2538 if (entry->rgb8_palette) { 2539 gst_memory_unref (entry->rgb8_palette); 2540 entry->rgb8_palette = NULL; 2541 } 2542 entry->sparse = FALSE; 2543 } 2544 2545 gst_tag_list_unref (stream->stream_tags); 2546 stream->stream_tags = gst_tag_list_new_empty (); 2547 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM); 2548 g_free (stream->redirect_uri); 2549 stream->redirect_uri = NULL; 2550 stream->sent_eos = FALSE; 2551 stream->protected = FALSE; 2552 if (stream->protection_scheme_info) { 2553 if (stream->protection_scheme_type == FOURCC_cenc) { 2554 QtDemuxCencSampleSetInfo *info = 2555 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info; 2556 if (info->default_properties) 2557 gst_structure_free (info->default_properties); 2558 if (info->crypto_info) 2559 g_ptr_array_free (info->crypto_info, TRUE); 2560 } 2561 g_free (stream->protection_scheme_info); 2562 stream->protection_scheme_info = NULL; 2563 } 2564 stream->protection_scheme_type = 0; 2565 stream->protection_scheme_version = 0; 2566 g_queue_foreach (&stream->protection_scheme_event_queue, 2567 (GFunc) gst_event_unref, NULL); 2568 g_queue_clear (&stream->protection_scheme_event_queue); 2569 gst_qtdemux_stream_flush_segments_data (qtdemux, stream); 2570 gst_qtdemux_stream_flush_samples_data (qtdemux, stream); 2571 } 2572 2573 static void 2574 gst_qtdemux_stream_reset (GstQTDemux * qtdemux, QtDemuxStream * stream) 2575 { 2576 gint i; 2577 gst_qtdemux_stream_clear (qtdemux, stream); 2578 for (i = 0; i < stream->stsd_entries_length; i++) { 2579 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i]; 2580 if (entry->caps) { 2581 gst_caps_unref (entry->caps); 2582 entry->caps = NULL; 2583 } 2584 } 2585 g_free (stream->stsd_entries); 2586 stream->stsd_entries = NULL; 2587 stream->stsd_entries_length = 0; 2588 } 2589 2590 2591 static void 2592 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream) 2593 { 2594 gst_qtdemux_stream_reset (qtdemux, stream); 2595 gst_tag_list_unref (stream->stream_tags); 2596 if (stream->pad) { 2597 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad); 2598 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad); 2599 } 2600 g_free (stream); 2601 } 2602 2603 static void 2604 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i) 2605 { 2606 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL); 2607 2608 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]); 2609 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1]; 2610 qtdemux->streams[qtdemux->n_streams - 1] = NULL; 2611 qtdemux->n_streams--; 2612 } 2613 2614 static GstStateChangeReturn 2615 gst_qtdemux_change_state (GstElement * element, GstStateChange transition) 2616 { 2617 GstQTDemux *qtdemux = GST_QTDEMUX (element); 2618 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; 2619 2620 switch (transition) { 2621 case GST_STATE_CHANGE_PAUSED_TO_READY: 2622 break; 2623 default: 2624 break; 2625 } 2626 2627 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); 2628 2629 switch (transition) { 2630 case GST_STATE_CHANGE_PAUSED_TO_READY:{ 2631 gst_qtdemux_reset (qtdemux, TRUE); 2632 break; 2633 } 2634 default: 2635 break; 2636 } 2637 2638 return result; 2639 } 2640 2641 static void 2642 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length) 2643 { 2644 /* counts as header data */ 2645 qtdemux->header_size += length; 2646 2647 /* only consider at least a sufficiently complete ftyp atom */ 2648 if (length >= 20) { 2649 GstBuffer *buf; 2650 2651 qtdemux->major_brand = QT_FOURCC (buffer + 8); 2652 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT, 2653 GST_FOURCC_ARGS (qtdemux->major_brand)); 2654 if (qtdemux->comp_brands) 2655 gst_buffer_unref (qtdemux->comp_brands); 2656 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16); 2657 gst_buffer_fill (buf, 0, buffer + 16, length - 16); 2658 } 2659 } 2660 2661 static void 2662 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist, 2663 GstTagList * xmptaglist) 2664 { 2665 /* Strip out bogus fields */ 2666 if (xmptaglist) { 2667 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) { 2668 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC); 2669 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC); 2670 } else { 2671 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT); 2672 } 2673 2674 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist); 2675 2676 /* prioritize native tags using _KEEP mode */ 2677 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP); 2678 gst_tag_list_unref (xmptaglist); 2679 } 2680 } 2681 2682 static void 2683 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length, 2684 guint offset) 2685 { 2686 GstByteReader br; 2687 guint8 version; 2688 guint32 flags = 0; 2689 guint i; 2690 guint8 iv_size = 8; 2691 QtDemuxStream *stream; 2692 GstStructure *structure; 2693 QtDemuxCencSampleSetInfo *ss_info = NULL; 2694 const gchar *system_id; 2695 gboolean uses_sub_sample_encryption = FALSE; 2696 guint32 sample_count; 2697 2698 if (qtdemux->n_streams == 0) 2699 return; 2700 2701 stream = qtdemux->streams[0]; 2702 2703 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0); 2704 if (!gst_structure_has_name (structure, "application/x-cenc")) { 2705 GST_WARNING_OBJECT (qtdemux, 2706 "Attempting PIFF box parsing on an unencrypted stream."); 2707 return; 2708 } 2709 2710 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, 2711 G_TYPE_STRING, &system_id, NULL); 2712 gst_qtdemux_append_protection_system_id (qtdemux, system_id); 2713 2714 stream->protected = TRUE; 2715 stream->protection_scheme_type = FOURCC_cenc; 2716 2717 if (!stream->protection_scheme_info) 2718 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1); 2719 2720 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info; 2721 2722 if (ss_info->default_properties) 2723 gst_structure_free (ss_info->default_properties); 2724 2725 ss_info->default_properties = 2726 gst_structure_new ("application/x-cenc", 2727 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL); 2728 2729 if (ss_info->crypto_info) { 2730 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info"); 2731 g_ptr_array_free (ss_info->crypto_info, TRUE); 2732 ss_info->crypto_info = NULL; 2733 } 2734 2735 /* skip UUID */ 2736 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16); 2737 2738 if (!gst_byte_reader_get_uint8 (&br, &version)) { 2739 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field"); 2740 return; 2741 } 2742 2743 if (!gst_byte_reader_get_uint24_be (&br, &flags)) { 2744 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field"); 2745 return; 2746 } 2747 2748 if ((flags & 0x000001)) { 2749 guint32 algorithm_id = 0; 2750 const guint8 *kid; 2751 GstBuffer *kid_buf; 2752 gboolean is_encrypted = TRUE; 2753 2754 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) { 2755 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field"); 2756 return; 2757 } 2758 2759 algorithm_id >>= 8; 2760 if (algorithm_id == 0) { 2761 is_encrypted = FALSE; 2762 } else if (algorithm_id == 1) { 2763 /* FIXME: maybe store this in properties? */ 2764 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream"); 2765 } else if (algorithm_id == 2) { 2766 /* FIXME: maybe store this in properties? */ 2767 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream"); 2768 } 2769 2770 if (!gst_byte_reader_get_uint8 (&br, &iv_size)) 2771 return; 2772 2773 if (!gst_byte_reader_get_data (&br, 16, &kid)) 2774 return; 2775 2776 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL); 2777 gst_buffer_fill (kid_buf, 0, kid, 16); 2778 if (ss_info->default_properties) 2779 gst_structure_free (ss_info->default_properties); 2780 ss_info->default_properties = 2781 gst_structure_new ("application/x-cenc", 2782 "iv_size", G_TYPE_UINT, iv_size, 2783 "encrypted", G_TYPE_BOOLEAN, is_encrypted, 2784 "kid", GST_TYPE_BUFFER, kid_buf, NULL); 2785 GST_DEBUG_OBJECT (qtdemux, "default sample properties: " 2786 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size); 2787 gst_buffer_unref (kid_buf); 2788 } else if ((flags & 0x000002)) { 2789 uses_sub_sample_encryption = TRUE; 2790 } 2791 2792 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) { 2793 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field"); 2794 return; 2795 } 2796 2797 ss_info->crypto_info = 2798 g_ptr_array_new_full (sample_count, 2799 (GDestroyNotify) qtdemux_gst_structure_free); 2800 2801 for (i = 0; i < sample_count; ++i) { 2802 GstStructure *properties; 2803 guint8 *data; 2804 GstBuffer *buf; 2805 2806 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i); 2807 if (properties == NULL) { 2808 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i); 2809 qtdemux->cenc_aux_sample_count = i; 2810 return; 2811 } 2812 2813 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) { 2814 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i); 2815 gst_structure_free (properties); 2816 qtdemux->cenc_aux_sample_count = i; 2817 return; 2818 } 2819 buf = gst_buffer_new_wrapped (data, iv_size); 2820 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL); 2821 gst_buffer_unref (buf); 2822 2823 if (uses_sub_sample_encryption) { 2824 guint16 n_subsamples; 2825 2826 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples) 2827 || n_subsamples == 0) { 2828 GST_ERROR_OBJECT (qtdemux, 2829 "failed to get subsample count for sample %u", i); 2830 gst_structure_free (properties); 2831 qtdemux->cenc_aux_sample_count = i; 2832 return; 2833 } 2834 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples); 2835 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) { 2836 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u", 2837 i); 2838 gst_structure_free (properties); 2839 qtdemux->cenc_aux_sample_count = i; 2840 return; 2841 } 2842 buf = gst_buffer_new_wrapped (data, n_subsamples * 6); 2843 gst_structure_set (properties, 2844 "subsample_count", G_TYPE_UINT, n_subsamples, 2845 "subsamples", GST_TYPE_BUFFER, buf, NULL); 2846 gst_buffer_unref (buf); 2847 } else { 2848 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL); 2849 } 2850 2851 g_ptr_array_add (ss_info->crypto_info, properties); 2852 } 2853 2854 qtdemux->cenc_aux_sample_count = sample_count; 2855 } 2856 2857 static void 2858 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length) 2859 { 2860 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB, 2861 0x97, 0xA9, 0x42, 0xE8, 2862 0x9C, 0x71, 0x99, 0x94, 2863 0x91, 0xE3, 0xAF, 0xAC 2864 }; 2865 static const guint8 playready_uuid[] = { 2866 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82, 2867 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3 2868 }; 2869 2870 static const guint8 piff_sample_encryption_uuid[] = { 2871 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14, 2872 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4 2873 }; 2874 2875 guint offset; 2876 2877 /* counts as header data */ 2878 qtdemux->header_size += length; 2879 2880 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8; 2881 2882 if (length <= offset + 16) { 2883 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping"); 2884 return; 2885 } 2886 2887 #ifndef GSTREAMER_LITE 2888 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) { 2889 GstBuffer *buf; 2890 GstTagList *taglist; 2891 2892 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16, 2893 length - offset - 16, NULL); 2894 taglist = gst_tag_list_from_xmp_buffer (buf); 2895 gst_buffer_unref (buf); 2896 2897 /* make sure we have a usable taglist */ 2898 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list); 2899 2900 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist); 2901 2902 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) { 2903 int len; 2904 const gunichar2 *s_utf16; 2905 char *contents; 2906 2907 len = GST_READ_UINT16_LE (buffer + offset + 0x30); 2908 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32); 2909 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL); 2910 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents); 2911 2912 g_free (contents); 2913 2914 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, 2915 (_("Cannot play stream because it is encrypted with PlayReady DRM.")), 2916 (NULL)); 2917 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) { 2918 qtdemux_parse_piff (qtdemux, buffer, length, offset); 2919 } else { 2920 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x", 2921 GST_READ_UINT32_LE (buffer + offset), 2922 GST_READ_UINT32_LE (buffer + offset + 4), 2923 GST_READ_UINT32_LE (buffer + offset + 8), 2924 GST_READ_UINT32_LE (buffer + offset + 12)); 2925 } 2926 #endif // GSTREAMER_LITE 2927 } 2928 2929 static void 2930 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length) 2931 { 2932 GstSidxParser sidx_parser; 2933 GstIsoffParserResult res; 2934 guint consumed; 2935 2936 gst_isoff_qt_sidx_parser_init (&sidx_parser); 2937 2938 res = 2939 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length, 2940 &consumed); 2941 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res); 2942 if (res == GST_ISOFF_QT_PARSER_DONE) { 2943 check_update_duration (qtdemux, sidx_parser.cumulative_pts); 2944 } 2945 gst_isoff_qt_sidx_parser_clear (&sidx_parser); 2946 } 2947 2948 /* caller verifies at least 8 bytes in buf */ 2949 static void 2950 extract_initial_length_and_fourcc (const guint8 * data, guint size, 2951 guint64 * plength, guint32 * pfourcc) 2952 { 2953 guint64 length; 2954 guint32 fourcc; 2955 2956 length = QT_UINT32 (data); 2957 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length); 2958 fourcc = QT_FOURCC (data + 4); 2959 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc)); 2960 2961 if (length == 0) { 2962 length = G_MAXUINT64; 2963 } else if (length == 1 && size >= 16) { 2964 /* this means we have an extended size, which is the 64 bit value of 2965 * the next 8 bytes */ 2966 length = QT_UINT64 (data + 8); 2967 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length); 2968 } 2969 2970 if (plength) 2971 *plength = length; 2972 if (pfourcc) 2973 *pfourcc = fourcc; 2974 } 2975 2976 static gboolean 2977 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br) 2978 { 2979 guint32 version = 0; 2980 GstClockTime duration = 0; 2981 2982 if (!gst_byte_reader_get_uint32_be (br, &version)) 2983 goto failed; 2984 2985 version >>= 24; 2986 if (version == 1) { 2987 if (!gst_byte_reader_get_uint64_be (br, &duration)) 2988 goto failed; 2989 } else { 2990 guint32 dur = 0; 2991 2992 if (!gst_byte_reader_get_uint32_be (br, &dur)) 2993 goto failed; 2994 duration = dur; 2995 } 2996 2997 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration); 2998 qtdemux->duration = duration; 2999 3000 return TRUE; 3001 3002 failed: 3003 { 3004 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed"); 3005 return FALSE; 3006 } 3007 } 3008 3009 static gboolean 3010 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream, 3011 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags) 3012 { 3013 if (!stream->parsed_trex && qtdemux->moov_node) { 3014 GNode *mvex, *trex; 3015 GstByteReader trex_data; 3016 3017 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex); 3018 if (mvex) { 3019 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex, 3020 &trex_data); 3021 while (trex) { 3022 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0; 3023 3024 /* skip version/flags */ 3025 if (!gst_byte_reader_skip (&trex_data, 4)) 3026 goto next; 3027 if (!gst_byte_reader_get_uint32_be (&trex_data, &id)) 3028 goto next; 3029 if (id != stream->track_id) 3030 goto next; 3031 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi)) 3032 goto next; 3033 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur)) 3034 goto next; 3035 if (!gst_byte_reader_get_uint32_be (&trex_data, &size)) 3036 goto next; 3037 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags)) 3038 goto next; 3039 3040 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; " 3041 "duration %d, size %d, flags 0x%x", stream->track_id, 3042 dur, size, flags); 3043 3044 stream->parsed_trex = TRUE; 3045 stream->def_sample_description_index = sdi; 3046 stream->def_sample_duration = dur; 3047 stream->def_sample_size = size; 3048 stream->def_sample_flags = flags; 3049 3050 next: 3051 /* iterate all siblings */ 3052 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex, 3053 &trex_data); 3054 } 3055 } 3056 } 3057 3058 *ds_duration = stream->def_sample_duration; 3059 *ds_size = stream->def_sample_size; 3060 *ds_flags = stream->def_sample_flags; 3061 3062 /* even then, above values are better than random ... */ 3063 if (G_UNLIKELY (!stream->parsed_trex)) { 3064 GST_WARNING_OBJECT (qtdemux, 3065 "failed to find fragment defaults for stream %d", stream->track_id); 3066 return FALSE; 3067 } 3068 3069 return TRUE; 3070 } 3071 3072 /* This method should be called whenever a more accurate duration might 3073 * have been found. It will update all relevant variables if/where needed 3074 */ 3075 static void 3076 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration) 3077 { 3078 guint i; 3079 guint64 movdur; 3080 GstClockTime prevdur; 3081 3082 movdur = GSTTIME_TO_QTTIME (qtdemux, duration); 3083 3084 if (movdur > qtdemux->duration) { 3085 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration); 3086 GST_DEBUG_OBJECT (qtdemux, 3087 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT, 3088 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur)); 3089 qtdemux->duration = movdur; 3090 GST_DEBUG_OBJECT (qtdemux, 3091 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %" 3092 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration), 3093 GST_TIME_ARGS (qtdemux->segment.stop)); 3094 if (qtdemux->segment.duration == prevdur) { 3095 /* If the current segment has duration/stop identical to previous duration 3096 * update them also (because they were set at that point in time with 3097 * the wrong duration */ 3098 /* We convert the value *from* the timescale version to avoid rounding errors */ 3099 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur); 3100 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop"); 3101 qtdemux->segment.duration = fixeddur; 3102 qtdemux->segment.stop = fixeddur; 3103 } 3104 } 3105 for (i = 0; i < qtdemux->n_streams; i++) { 3106 QtDemuxStream *stream = qtdemux->streams[i]; 3107 if (stream) { 3108 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration); 3109 if (movdur > stream->duration) { 3110 GST_DEBUG_OBJECT (qtdemux, 3111 "Updating stream #%d duration to %" GST_TIME_FORMAT, i, 3112 GST_TIME_ARGS (duration)); 3113 stream->duration = movdur; 3114 /* internal duration tracking state has been updated above, so */ 3115 /* preserve an open-ended dummy segment rather than repeatedly updating 3116 * it and spamming downstream accordingly with segment events */ 3117 if (stream->dummy_segment && 3118 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) { 3119 /* Update all dummy values to new duration */ 3120 stream->segments[0].stop_time = duration; 3121 stream->segments[0].duration = duration; 3122 stream->segments[0].media_stop = duration; 3123 3124 /* let downstream know we possibly have a new stop time */ 3125 if (stream->segment_index != -1) { 3126 GstClockTime pos; 3127 3128 if (qtdemux->segment.rate >= 0) { 3129 pos = stream->segment.start; 3130 } else { 3131 pos = stream->segment.stop; 3132 } 3133 3134 gst_qtdemux_stream_update_segment (qtdemux, stream, 3135 stream->segment_index, pos, NULL, NULL); 3136 } 3137 } 3138 } 3139 } 3140 } 3141 } 3142 3143 static gboolean 3144 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun, 3145 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size, 3146 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length, 3147 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts, 3148 gboolean has_tfdt) 3149 { 3150 GstClockTime gst_ts = GST_CLOCK_TIME_NONE; 3151 guint64 timestamp; 3152 gint32 data_offset = 0; 3153 guint32 flags = 0, first_flags = 0, samples_count = 0; 3154 gint i; 3155 guint8 *data; 3156 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0; 3157 QtDemuxSample *sample; 3158 gboolean ismv = FALSE; 3159 gint64 initial_offset; 3160 3161 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; " 3162 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", " 3163 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration, 3164 d_sample_size, d_sample_flags, *base_offset, decode_ts); 3165 3166 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) { 3167 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment"); 3168 return TRUE; 3169 } 3170 3171 /* presence of stss or not can't really tell us much, 3172 * and flags and so on tend to be marginally reliable in these files */ 3173 if (stream->subtype == FOURCC_soun) { 3174 GST_DEBUG_OBJECT (qtdemux, 3175 "sound track in fragmented file; marking all keyframes"); 3176 stream->all_keyframe = TRUE; 3177 } 3178 3179 if (!gst_byte_reader_skip (trun, 1) || 3180 !gst_byte_reader_get_uint24_be (trun, &flags)) 3181 goto fail; 3182 3183 if (!gst_byte_reader_get_uint32_be (trun, &samples_count)) 3184 goto fail; 3185 3186 if (flags & TR_DATA_OFFSET) { 3187 /* note this is really signed */ 3188 if (!gst_byte_reader_get_int32_be (trun, &data_offset)) 3189 goto fail; 3190 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset); 3191 /* default base offset = first byte of moof */ 3192 if (*base_offset == -1) { 3193 GST_LOG_OBJECT (qtdemux, "base_offset at moof"); 3194 *base_offset = moof_offset; 3195 } 3196 *running_offset = *base_offset + data_offset; 3197 } else { 3198 /* if no offset at all, that would mean data starts at moof start, 3199 * which is a bit wrong and is ismv crappy way, so compensate 3200 * assuming data is in mdat following moof */ 3201 if (*base_offset == -1) { 3202 *base_offset = moof_offset + moof_length + 8; 3203 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof"); 3204 ismv = TRUE; 3205 } 3206 if (*running_offset == -1) 3207 *running_offset = *base_offset; 3208 } 3209 3210 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT, 3211 *running_offset); 3212 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d", 3213 data_offset, flags, samples_count); 3214 3215 if (flags & TR_FIRST_SAMPLE_FLAGS) { 3216 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) { 3217 GST_DEBUG_OBJECT (qtdemux, 3218 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter"); 3219 flags ^= TR_FIRST_SAMPLE_FLAGS; 3220 } else { 3221 if (!gst_byte_reader_get_uint32_be (trun, &first_flags)) 3222 goto fail; 3223 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags); 3224 } 3225 } 3226 3227 /* FIXME ? spec says other bits should also be checked to determine 3228 * entry size (and prefix size for that matter) */ 3229 entry_size = 0; 3230 dur_offset = size_offset = 0; 3231 if (flags & TR_SAMPLE_DURATION) { 3232 GST_LOG_OBJECT (qtdemux, "entry duration present"); 3233 dur_offset = entry_size; 3234 entry_size += 4; 3235 } 3236 if (flags & TR_SAMPLE_SIZE) { 3237 GST_LOG_OBJECT (qtdemux, "entry size present"); 3238 size_offset = entry_size; 3239 entry_size += 4; 3240 } 3241 if (flags & TR_SAMPLE_FLAGS) { 3242 GST_LOG_OBJECT (qtdemux, "entry flags present"); 3243 flags_offset = entry_size; 3244 entry_size += 4; 3245 } 3246 if (flags & TR_COMPOSITION_TIME_OFFSETS) { 3247 GST_LOG_OBJECT (qtdemux, "entry ct offset present"); 3248 ct_offset = entry_size; 3249 entry_size += 4; 3250 } 3251 3252 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size)) 3253 goto fail; 3254 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun); 3255 3256 if (stream->n_samples + samples_count >= 3257 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) 3258 goto index_too_big; 3259 3260 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)", 3261 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample), 3262 (stream->n_samples + samples_count) * 3263 sizeof (QtDemuxSample) / (1024.0 * 1024.0)); 3264 3265 /* create a new array of samples if it's the first sample parsed */ 3266 if (stream->n_samples == 0) { 3267 g_assert (stream->samples == NULL); 3268 stream->samples = g_try_new0 (QtDemuxSample, samples_count); 3269 /* or try to reallocate it with space enough to insert the new samples */ 3270 } else 3271 stream->samples = g_try_renew (QtDemuxSample, stream->samples, 3272 stream->n_samples + samples_count); 3273 if (stream->samples == NULL) 3274 goto out_of_memory; 3275 3276 if (qtdemux->fragment_start != -1) { 3277 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start); 3278 qtdemux->fragment_start = -1; 3279 } else { 3280 if (stream->n_samples == 0) { 3281 if (decode_ts > 0) { 3282 timestamp = decode_ts; 3283 } else if (stream->pending_seek != NULL) { 3284 /* if we don't have a timestamp from a tfdt box, we'll use the one 3285 * from the mfra seek table */ 3286 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT, 3287 GST_TIME_ARGS (stream->pending_seek->ts)); 3288 3289 /* FIXME: this is not fully correct, the timestamp refers to the random 3290 * access sample refered to in the tfra entry, which may not necessarily 3291 * be the first sample in the tfrag/trun (but hopefully/usually is) */ 3292 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts); 3293 } else { 3294 timestamp = 0; 3295 } 3296 3297 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp); 3298 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT, 3299 GST_TIME_ARGS (gst_ts)); 3300 } else { 3301 /* subsequent fragments extend stream */ 3302 timestamp = 3303 stream->samples[stream->n_samples - 1].timestamp + 3304 stream->samples[stream->n_samples - 1].duration; 3305 3306 /* If this is a GST_FORMAT_BYTES stream and there's a significant 3307 * difference (1 sec.) between decode_ts and timestamp, prefer the 3308 * former */ 3309 if (has_tfdt && !qtdemux->upstream_format_is_time 3310 && ABSDIFF (decode_ts, timestamp) > 3311 MAX (stream->duration_last_moof / 2, 3312 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) { 3313 GST_INFO_OBJECT (qtdemux, 3314 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT 3315 ") are significantly different (more than %" GST_TIME_FORMAT 3316 "), using decode_ts", 3317 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)), 3318 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)), 3319 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, 3320 MAX (stream->duration_last_moof / 2, 3321 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))))); 3322 timestamp = decode_ts; 3323 } 3324 3325 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp); 3326 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT 3327 " (extends previous samples)", GST_TIME_ARGS (gst_ts)); 3328 } 3329 } 3330 3331 initial_offset = *running_offset; 3332 3333 sample = stream->samples + stream->n_samples; 3334 for (i = 0; i < samples_count; i++) { 3335 guint32 dur, size, sflags, ct; 3336 3337 /* first read sample data */ 3338 if (flags & TR_SAMPLE_DURATION) { 3339 dur = QT_UINT32 (data + dur_offset); 3340 } else { 3341 dur = d_sample_duration; 3342 } 3343 if (flags & TR_SAMPLE_SIZE) { 3344 size = QT_UINT32 (data + size_offset); 3345 } else { 3346 size = d_sample_size; 3347 } 3348 if (flags & TR_FIRST_SAMPLE_FLAGS) { 3349 if (i == 0) { 3350 sflags = first_flags; 3351 } else { 3352 sflags = d_sample_flags; 3353 } 3354 } else if (flags & TR_SAMPLE_FLAGS) { 3355 sflags = QT_UINT32 (data + flags_offset); 3356 } else { 3357 sflags = d_sample_flags; 3358 } 3359 if (flags & TR_COMPOSITION_TIME_OFFSETS) { 3360 ct = QT_UINT32 (data + ct_offset); 3361 } else { 3362 ct = 0; 3363 } 3364 data += entry_size; 3365 3366 /* fill the sample information */ 3367 sample->offset = *running_offset; 3368 sample->pts_offset = ct; 3369 sample->size = size; 3370 sample->timestamp = timestamp; 3371 sample->duration = dur; 3372 /* sample-is-difference-sample */ 3373 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe, 3374 * now idea how it relates to bitfield other than massive LE/BE confusion */ 3375 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000); 3376 *running_offset += size; 3377 timestamp += dur; 3378 stream->duration_moof += dur; 3379 sample++; 3380 } 3381 3382 /* Update total duration if needed */ 3383 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp)); 3384 3385 /* Pre-emptively figure out size of mdat based on trun information. 3386 * If the [mdat] atom is effectivelly read, it will be replaced by the actual 3387 * size, else we will still be able to use this when dealing with gap'ed 3388 * input */ 3389 qtdemux->mdatleft = *running_offset - initial_offset; 3390 qtdemux->mdatoffset = initial_offset; 3391 qtdemux->mdatsize = qtdemux->mdatleft; 3392 3393 stream->n_samples += samples_count; 3394 stream->n_samples_moof += samples_count; 3395 3396 if (stream->pending_seek != NULL) 3397 stream->pending_seek = NULL; 3398 3399 return TRUE; 3400 3401 fail: 3402 { 3403 GST_WARNING_OBJECT (qtdemux, "failed to parse trun"); 3404 return FALSE; 3405 } 3406 out_of_memory: 3407 { 3408 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples", 3409 stream->n_samples); 3410 return FALSE; 3411 } 3412 index_too_big: 3413 { 3414 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would " 3415 "be larger than %uMB (broken file?)", stream->n_samples, 3416 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20); 3417 return FALSE; 3418 } 3419 } 3420 3421 /* find stream with @id */ 3422 static inline QtDemuxStream * 3423 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id) 3424 { 3425 QtDemuxStream *stream; 3426 gint i; 3427 3428 /* check */ 3429 if (G_UNLIKELY (!id)) { 3430 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0"); 3431 return NULL; 3432 } 3433 3434 /* try to get it fast and simple */ 3435 if (G_LIKELY (id <= qtdemux->n_streams)) { 3436 stream = qtdemux->streams[id - 1]; 3437 if (G_LIKELY (stream->track_id == id)) 3438 return stream; 3439 } 3440 3441 /* linear search otherwise */ 3442 for (i = 0; i < qtdemux->n_streams; i++) { 3443 stream = qtdemux->streams[i]; 3444 if (stream->track_id == id) 3445 return stream; 3446 } 3447 if (qtdemux->mss_mode) { 3448 /* mss should have only 1 stream anyway */ 3449 return qtdemux->streams[0]; 3450 } 3451 3452 return NULL; 3453 } 3454 3455 static gboolean 3456 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd, 3457 guint32 * fragment_number) 3458 { 3459 if (!gst_byte_reader_skip (mfhd, 4)) 3460 goto fail; 3461 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number)) 3462 goto fail; 3463 return TRUE; 3464 fail: 3465 { 3466 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom"); 3467 return FALSE; 3468 } 3469 } 3470 3471 static gboolean 3472 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd, 3473 QtDemuxStream ** stream, guint32 * default_sample_duration, 3474 guint32 * default_sample_size, guint32 * default_sample_flags, 3475 gint64 * base_offset) 3476 { 3477 guint32 flags = 0; 3478 guint32 track_id = 0; 3479 3480 if (!gst_byte_reader_skip (tfhd, 1) || 3481 !gst_byte_reader_get_uint24_be (tfhd, &flags)) 3482 goto invalid_track; 3483 3484 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id)) 3485 goto invalid_track; 3486 3487 *stream = qtdemux_find_stream (qtdemux, track_id); 3488 if (G_UNLIKELY (!*stream)) 3489 goto unknown_stream; 3490 3491 if (flags & TF_DEFAULT_BASE_IS_MOOF) 3492 *base_offset = qtdemux->moof_offset; 3493 3494 if (flags & TF_BASE_DATA_OFFSET) 3495 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset)) 3496 goto invalid_track; 3497 3498 /* obtain stream defaults */ 3499 qtdemux_parse_trex (qtdemux, *stream, 3500 default_sample_duration, default_sample_size, default_sample_flags); 3501 3502 (*stream)->stsd_sample_description_id = 3503 (*stream)->def_sample_description_index - 1; 3504 3505 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) { 3506 guint32 sample_description_index; 3507 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index)) 3508 goto invalid_track; 3509 (*stream)->stsd_sample_description_id = sample_description_index - 1; 3510 } 3511 3512 if (qtdemux->mss_mode) { 3513 /* mss has no stsd entry */ 3514 (*stream)->stsd_sample_description_id = 0; 3515 } 3516 3517 if (flags & TF_DEFAULT_SAMPLE_DURATION) 3518 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration)) 3519 goto invalid_track; 3520 3521 if (flags & TF_DEFAULT_SAMPLE_SIZE) 3522 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size)) 3523 goto invalid_track; 3524 3525 if (flags & TF_DEFAULT_SAMPLE_FLAGS) 3526 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags)) 3527 goto invalid_track; 3528 3529 return TRUE; 3530 3531 invalid_track: 3532 { 3533 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header"); 3534 return FALSE; 3535 } 3536 unknown_stream: 3537 { 3538 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd"); 3539 return TRUE; 3540 } 3541 } 3542 3543 static gboolean 3544 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br, 3545 guint64 * decode_time) 3546 { 3547 guint32 version = 0; 3548 3549 if (!gst_byte_reader_get_uint32_be (br, &version)) 3550 return FALSE; 3551 3552 version >>= 24; 3553 if (version == 1) { 3554 if (!gst_byte_reader_get_uint64_be (br, decode_time)) 3555 goto failed; 3556 } else { 3557 guint32 dec_time = 0; 3558 if (!gst_byte_reader_get_uint32_be (br, &dec_time)) 3559 goto failed; 3560 *decode_time = dec_time; 3561 } 3562 3563 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT, 3564 *decode_time); 3565 3566 return TRUE; 3567 3568 failed: 3569 { 3570 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed"); 3571 return FALSE; 3572 } 3573 } 3574 3575 /* Returns a pointer to a GstStructure containing the properties of 3576 * the stream sample identified by @sample_index. The caller must unref 3577 * the returned object after use. Returns NULL if unsuccessful. */ 3578 static GstStructure * 3579 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux, 3580 QtDemuxStream * stream, guint sample_index) 3581 { 3582 QtDemuxCencSampleSetInfo *info = NULL; 3583 3584 g_return_val_if_fail (stream != NULL, NULL); 3585 g_return_val_if_fail (stream->protected, NULL); 3586 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL); 3587 3588 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info; 3589 3590 /* Currently, cenc properties for groups of samples are not supported, so 3591 * simply return a copy of the default sample properties */ 3592 return gst_structure_copy (info->default_properties); 3593 } 3594 3595 /* Parses the sizes of sample auxiliary information contained within a stream, 3596 * as given in a saiz box. Returns array of sample_count guint8 size values, 3597 * or NULL on failure */ 3598 static guint8 * 3599 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream, 3600 GstByteReader * br, guint32 * sample_count) 3601 { 3602 guint32 flags = 0; 3603 guint8 *info_sizes; 3604 guint8 default_info_size; 3605 3606 g_return_val_if_fail (qtdemux != NULL, NULL); 3607 g_return_val_if_fail (stream != NULL, NULL); 3608 g_return_val_if_fail (br != NULL, NULL); 3609 g_return_val_if_fail (sample_count != NULL, NULL); 3610 3611 if (!gst_byte_reader_get_uint32_be (br, &flags)) 3612 return NULL; 3613 3614 if (flags & 0x1) { 3615 /* aux_info_type and aux_info_type_parameter are ignored */ 3616 if (!gst_byte_reader_skip (br, 8)) 3617 return NULL; 3618 } 3619 3620 if (!gst_byte_reader_get_uint8 (br, &default_info_size)) 3621 return NULL; 3622 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size); 3623 3624 if (!gst_byte_reader_get_uint32_be (br, sample_count)) 3625 return NULL; 3626 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count); 3627 3628 3629 if (default_info_size == 0) { 3630 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) { 3631 return NULL; 3632 } 3633 } else { 3634 info_sizes = g_new (guint8, *sample_count); 3635 memset (info_sizes, default_info_size, *sample_count); 3636 } 3637 3638 return info_sizes; 3639 } 3640 3641 /* Parses the offset of sample auxiliary information contained within a stream, 3642 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */ 3643 static gboolean 3644 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream, 3645 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter, 3646 guint64 * offset) 3647 { 3648 guint8 version = 0; 3649 guint32 flags = 0; 3650 guint32 aux_info_type = 0; 3651 guint32 aux_info_type_parameter = 0; 3652 guint32 entry_count; 3653 guint32 off_32; 3654 guint64 off_64; 3655 const guint8 *aux_info_type_data = NULL; 3656 3657 g_return_val_if_fail (qtdemux != NULL, FALSE); 3658 g_return_val_if_fail (stream != NULL, FALSE); 3659 g_return_val_if_fail (br != NULL, FALSE); 3660 g_return_val_if_fail (offset != NULL, FALSE); 3661 3662 if (!gst_byte_reader_get_uint8 (br, &version)) 3663 return FALSE; 3664 3665 if (!gst_byte_reader_get_uint24_be (br, &flags)) 3666 return FALSE; 3667 3668 if (flags & 0x1) { 3669 3670 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data)) 3671 return FALSE; 3672 aux_info_type = QT_FOURCC (aux_info_type_data); 3673 3674 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter)) 3675 return FALSE; 3676 } else if (stream->protected) { 3677 aux_info_type = stream->protection_scheme_type; 3678 } else { 3679 aux_info_type = CUR_STREAM (stream)->fourcc; 3680 } 3681 3682 if (info_type) 3683 *info_type = aux_info_type; 3684 if (info_type_parameter) 3685 *info_type_parameter = aux_info_type_parameter; 3686 3687 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', " 3688 "aux_info_type_parameter: %#06x", 3689 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter); 3690 3691 if (!gst_byte_reader_get_uint32_be (br, &entry_count)) 3692 return FALSE; 3693 3694 if (entry_count != 1) { 3695 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported"); 3696 return FALSE; 3697 } 3698 3699 if (version == 0) { 3700 if (!gst_byte_reader_get_uint32_be (br, &off_32)) 3701 return FALSE; 3702 *offset = (guint64) off_32; 3703 } else { 3704 if (!gst_byte_reader_get_uint64_be (br, &off_64)) 3705 return FALSE; 3706 *offset = off_64; 3707 } 3708 3709 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset); 3710 return TRUE; 3711 } 3712 3713 static void 3714 qtdemux_gst_structure_free (GstStructure * gststructure) 3715 { 3716 if (gststructure) { 3717 gst_structure_free (gststructure); 3718 } 3719 } 3720 3721 /* Parses auxiliary information relating to samples protected using Common 3722 * Encryption (cenc); the format of this information is defined in 3723 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */ 3724 static gboolean 3725 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream, 3726 GstByteReader * br, guint8 * info_sizes, guint32 sample_count) 3727 { 3728 QtDemuxCencSampleSetInfo *ss_info = NULL; 3729 guint8 size; 3730 gint i; 3731 GPtrArray *old_crypto_info = NULL; 3732 guint old_entries = 0; 3733 3734 g_return_val_if_fail (qtdemux != NULL, FALSE); 3735 g_return_val_if_fail (stream != NULL, FALSE); 3736 g_return_val_if_fail (br != NULL, FALSE); 3737 g_return_val_if_fail (stream->protected, FALSE); 3738 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE); 3739 3740 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info; 3741 3742 if (ss_info->crypto_info) { 3743 old_crypto_info = ss_info->crypto_info; 3744 /* Count number of non-null entries remaining at the tail end */ 3745 for (i = old_crypto_info->len - 1; i >= 0; i--) { 3746 if (g_ptr_array_index (old_crypto_info, i) == NULL) 3747 break; 3748 old_entries++; 3749 } 3750 } 3751 3752 ss_info->crypto_info = 3753 g_ptr_array_new_full (sample_count + old_entries, 3754 (GDestroyNotify) qtdemux_gst_structure_free); 3755 3756 /* We preserve old entries because we parse the next moof in advance 3757 * of consuming all samples from the previous moof, and otherwise 3758 * we'd discard the corresponding crypto info for the samples 3759 * from the previous fragment. */ 3760 if (old_entries) { 3761 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries", 3762 old_entries); 3763 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) { 3764 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info, 3765 i)); 3766 g_ptr_array_index (old_crypto_info, i) = NULL; 3767 } 3768 } 3769 3770 if (old_crypto_info) { 3771 /* Everything now belongs to the new array */ 3772 g_ptr_array_free (old_crypto_info, TRUE); 3773 } 3774 3775 for (i = 0; i < sample_count; ++i) { 3776 GstStructure *properties; 3777 guint16 n_subsamples = 0; 3778 guint8 *data; 3779 guint iv_size; 3780 GstBuffer *buf; 3781 3782 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i); 3783 if (properties == NULL) { 3784 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i); 3785 return FALSE; 3786 } 3787 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) { 3788 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i); 3789 gst_structure_free (properties); 3790 return FALSE; 3791 } 3792 if (!gst_byte_reader_dup_data (br, iv_size, &data)) { 3793 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i); 3794 gst_structure_free (properties); 3795 return FALSE; 3796 } 3797 buf = gst_buffer_new_wrapped (data, iv_size); 3798 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL); 3799 gst_buffer_unref (buf); 3800 size = info_sizes[i]; 3801 if (size > iv_size) { 3802 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples) 3803 || !(n_subsamples > 0)) { 3804 gst_structure_free (properties); 3805 GST_ERROR_OBJECT (qtdemux, 3806 "failed to get subsample count for sample %u", i); 3807 return FALSE; 3808 } 3809 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples); 3810 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) { 3811 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u", 3812 i); 3813 gst_structure_free (properties); 3814 return FALSE; 3815 } 3816 buf = gst_buffer_new_wrapped (data, n_subsamples * 6); 3817 if (!buf) { 3818 gst_structure_free (properties); 3819 return FALSE; 3820 } 3821 gst_structure_set (properties, 3822 "subsample_count", G_TYPE_UINT, n_subsamples, 3823 "subsamples", GST_TYPE_BUFFER, buf, NULL); 3824 gst_buffer_unref (buf); 3825 } else { 3826 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL); 3827 } 3828 g_ptr_array_add (ss_info->crypto_info, properties); 3829 } 3830 return TRUE; 3831 } 3832 3833 /* Converts a UUID in raw byte form to a string representation, as defined in 3834 * RFC 4122. The caller takes ownership of the returned string and is 3835 * responsible for freeing it after use. */ 3836 static gchar * 3837 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes) 3838 { 3839 const guint8 *uuid = (const guint8 *) uuid_bytes; 3840 3841 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-" 3842 "%02x%02x-%02x%02x%02x%02x%02x%02x", 3843 uuid[0], uuid[1], uuid[2], uuid[3], 3844 uuid[4], uuid[5], uuid[6], uuid[7], 3845 uuid[8], uuid[9], uuid[10], uuid[11], 3846 uuid[12], uuid[13], uuid[14], uuid[15]); 3847 } 3848 3849 /* Parses a Protection System Specific Header box (pssh), as defined in the 3850 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains 3851 * information needed by a specific content protection system in order to 3852 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE 3853 * otherwise. */ 3854 static gboolean 3855 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node) 3856 { 3857 gchar *sysid_string; 3858 guint32 pssh_size = QT_UINT32 (node->data); 3859 GstBuffer *pssh = NULL; 3860 GstEvent *event = NULL; 3861 guint32 parent_box_type; 3862 gint i; 3863 3864 if (G_UNLIKELY (pssh_size < 32U)) { 3865 GST_ERROR_OBJECT (qtdemux, "invalid box size"); 3866 return FALSE; 3867 } 3868 3869 sysid_string = 3870 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12); 3871 3872 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string); 3873 3874 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size); 3875 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT, 3876 gst_buffer_get_size (pssh)); 3877 3878 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4); 3879 3880 /* Push an event containing the pssh box onto the queues of all streams. */ 3881 event = gst_event_new_protection (sysid_string, pssh, 3882 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof"); 3883 for (i = 0; i < qtdemux->n_streams; ++i) { 3884 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue, 3885 gst_event_ref (event)); 3886 } 3887 g_free (sysid_string); 3888 gst_event_unref (event); 3889 gst_buffer_unref (pssh); 3890 return TRUE; 3891 } 3892 3893 static gboolean 3894 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length, 3895 guint64 moof_offset, QtDemuxStream * stream) 3896 { 3897 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node; 3898 GNode *uuid_node; 3899 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data; 3900 GNode *saiz_node, *saio_node, *pssh_node; 3901 GstByteReader saiz_data, saio_data; 3902 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0; 3903 gint64 base_offset, running_offset; 3904 guint32 frag_num; 3905 3906 /* NOTE @stream ignored */ 3907 3908 moof_node = g_node_new ((guint8 *) buffer); 3909 qtdemux_parse_node (qtdemux, moof_node, buffer, length); 3910 qtdemux_node_dump (qtdemux, moof_node); 3911 3912 /* Get fragment number from mfhd and check it's valid */ 3913 mfhd_node = 3914 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data); 3915 if (mfhd_node == NULL) 3916 goto missing_mfhd; 3917 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num)) 3918 goto fail; 3919 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num); 3920 3921 /* unknown base_offset to start with */ 3922 base_offset = running_offset = -1; 3923 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf); 3924 while (traf_node) { 3925 guint64 decode_time = 0; 3926 3927 /* Fragment Header node */ 3928 tfhd_node = 3929 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd, 3930 &tfhd_data); 3931 if (!tfhd_node) 3932 goto missing_tfhd; 3933 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration, 3934 &ds_size, &ds_flags, &base_offset)) 3935 goto missing_tfhd; 3936 3937 /* The following code assumes at most a single set of sample auxiliary 3938 * data in the fragment (consisting of a saiz box and a corresponding saio 3939 * box); in theory, however, there could be multiple sets of sample 3940 * auxiliary data in a fragment. */ 3941 saiz_node = 3942 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz, 3943 &saiz_data); 3944 if (saiz_node) { 3945 guint32 info_type = 0; 3946 guint64 offset = 0; 3947 guint32 info_type_parameter = 0; 3948 3949 g_free (qtdemux->cenc_aux_info_sizes); 3950 3951 qtdemux->cenc_aux_info_sizes = 3952 qtdemux_parse_saiz (qtdemux, stream, &saiz_data, 3953 &qtdemux->cenc_aux_sample_count); 3954 if (qtdemux->cenc_aux_info_sizes == NULL) { 3955 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box"); 3956 goto fail; 3957 } 3958 saio_node = 3959 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio, 3960 &saio_data); 3961 if (!saio_node) { 3962 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box"); 3963 g_free (qtdemux->cenc_aux_info_sizes); 3964 qtdemux->cenc_aux_info_sizes = NULL; 3965 goto fail; 3966 } 3967 3968 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data, 3969 &info_type, &info_type_parameter, &offset))) { 3970 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box"); 3971 g_free (qtdemux->cenc_aux_info_sizes); 3972 qtdemux->cenc_aux_info_sizes = NULL; 3973 goto fail; 3974 } 3975 if (base_offset > -1 && base_offset > qtdemux->moof_offset) 3976 offset += (guint64) (base_offset - qtdemux->moof_offset); 3977 if (info_type == FOURCC_cenc && info_type_parameter == 0U) { 3978 GstByteReader br; 3979 if (offset > length) { 3980 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof"); 3981 qtdemux->cenc_aux_info_offset = offset; 3982 } else { 3983 gst_byte_reader_init (&br, buffer + offset, length - offset); 3984 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br, 3985 qtdemux->cenc_aux_info_sizes, 3986 qtdemux->cenc_aux_sample_count)) { 3987 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info"); 3988 g_free (qtdemux->cenc_aux_info_sizes); 3989 qtdemux->cenc_aux_info_sizes = NULL; 3990 goto fail; 3991 } 3992 } 3993 } 3994 } 3995 3996 tfdt_node = 3997 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt, 3998 &tfdt_data); 3999 if (tfdt_node) { 4000 /* We'll use decode_time to interpolate timestamps 4001 * in case the input timestamps are missing */ 4002 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time); 4003 4004 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT 4005 " (%" GST_TIME_FORMAT ")", decode_time, 4006 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream, 4007 decode_time) : GST_CLOCK_TIME_NONE)); 4008 4009 /* Discard the fragment buffer timestamp info to avoid using it. 4010 * Rely on tfdt instead as it is more accurate than the timestamp 4011 * that is fetched from a manifest/playlist and is usually 4012 * less accurate. */ 4013 qtdemux->fragment_start = -1; 4014 } 4015 4016 if (G_UNLIKELY (!stream)) { 4017 /* we lost track of offset, we'll need to regain it, 4018 * but can delay complaining until later or avoid doing so altogether */ 4019 base_offset = -2; 4020 goto next; 4021 } 4022 if (G_UNLIKELY (base_offset < -1)) 4023 goto lost_offset; 4024 4025 if (qtdemux->upstream_format_is_time) 4026 gst_qtdemux_stream_flush_samples_data (qtdemux, stream); 4027 4028 /* initialise moof sample data */ 4029 stream->n_samples_moof = 0; 4030 stream->duration_last_moof = stream->duration_moof; 4031 stream->duration_moof = 0; 4032 4033 /* Track Run node */ 4034 trun_node = 4035 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun, 4036 &trun_data); 4037 while (trun_node) { 4038 qtdemux_parse_trun (qtdemux, &trun_data, stream, 4039 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset, 4040 &running_offset, decode_time, (tfdt_node != NULL)); 4041 /* iterate all siblings */ 4042 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun, 4043 &trun_data); 4044 } 4045 4046 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid); 4047 if (uuid_node) { 4048 guint8 *uuid_buffer = (guint8 *) uuid_node->data; 4049 guint32 box_length = QT_UINT32 (uuid_buffer); 4050 4051 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length); 4052 } 4053 4054 /* if no new base_offset provided for next traf, 4055 * base is end of current traf */ 4056 base_offset = running_offset; 4057 running_offset = -1; 4058 4059 if (stream->n_samples_moof && stream->duration_moof) 4060 stream->new_caps = TRUE; 4061 4062 next: 4063 /* iterate all siblings */ 4064 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf); 4065 } 4066 4067 /* parse any protection system info */ 4068 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh); 4069 while (pssh_node) { 4070 GST_LOG_OBJECT (qtdemux, "Parsing pssh box."); 4071 qtdemux_parse_pssh (qtdemux, pssh_node); 4072 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh); 4073 } 4074 4075 g_node_destroy (moof_node); 4076 return TRUE; 4077 4078 missing_tfhd: 4079 { 4080 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box"); 4081 goto fail; 4082 } 4083 missing_mfhd: 4084 { 4085 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box"); 4086 goto fail; 4087 } 4088 lost_offset: 4089 { 4090 GST_DEBUG_OBJECT (qtdemux, "lost offset"); 4091 goto fail; 4092 } 4093 fail: 4094 { 4095 g_node_destroy (moof_node); 4096 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX, 4097 (_("This file is corrupt and cannot be played.")), (NULL)); 4098 return FALSE; 4099 } 4100 } 4101 4102 #if 0 4103 /* might be used if some day we actually use mfra & co 4104 * for random access to fragments, 4105 * but that will require quite some modifications and much less relying 4106 * on a sample array */ 4107 #endif 4108 4109 static gboolean 4110 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node) 4111 { 4112 QtDemuxStream *stream; 4113 guint32 ver_flags, track_id, len, num_entries, i; 4114 guint value_size, traf_size, trun_size, sample_size; 4115 guint64 time = 0, moof_offset = 0; 4116 #if 0 4117 GstBuffer *buf = NULL; 4118 GstFlowReturn ret; 4119 #endif 4120 GstByteReader tfra; 4121 4122 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data)); 4123 4124 if (!gst_byte_reader_skip (&tfra, 8)) 4125 return FALSE; 4126 4127 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags)) 4128 return FALSE; 4129 4130 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id) 4131 || !gst_byte_reader_get_uint32_be (&tfra, &len) 4132 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries)) 4133 return FALSE; 4134 4135 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id); 4136 4137 stream = qtdemux_find_stream (qtdemux, track_id); 4138 if (stream == NULL) 4139 goto unknown_trackid; 4140 4141 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32); 4142 sample_size = (len & 3) + 1; 4143 trun_size = ((len & 12) >> 2) + 1; 4144 traf_size = ((len & 48) >> 4) + 1; 4145 4146 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, " 4147 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size); 4148 4149 if (num_entries == 0) 4150 goto no_samples; 4151 4152 if (!qt_atom_parser_has_chunks (&tfra, num_entries, 4153 value_size + value_size + traf_size + trun_size + sample_size)) 4154 goto corrupt_file; 4155 4156 g_free (stream->ra_entries); 4157 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries); 4158 stream->n_ra_entries = num_entries; 4159 4160 for (i = 0; i < num_entries; i++) { 4161 qt_atom_parser_get_offset (&tfra, value_size, &time); 4162 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset); 4163 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size); 4164 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size); 4165 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size); 4166 4167 time = QTSTREAMTIME_TO_GSTTIME (stream, time); 4168 4169 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", " 4170 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset); 4171 4172 stream->ra_entries[i].ts = time; 4173 stream->ra_entries[i].moof_offset = moof_offset; 4174 4175 /* don't want to go through the entire file and read all moofs at startup */ 4176 #if 0 4177 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf); 4178 if (ret != GST_FLOW_OK) 4179 goto corrupt_file; 4180 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), 4181 moof_offset, stream); 4182 gst_buffer_unref (buf); 4183 #endif 4184 } 4185 4186 check_update_duration (qtdemux, time); 4187 4188 return TRUE; 4189 4190 /* ERRORS */ 4191 unknown_trackid: 4192 { 4193 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id); 4194 return FALSE; 4195 } 4196 corrupt_file: 4197 { 4198 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring"); 4199 return FALSE; 4200 } 4201 no_samples: 4202 { 4203 GST_WARNING_OBJECT (qtdemux, "stream has no samples"); 4204 return FALSE; 4205 } 4206 } 4207 4208 static gboolean 4209 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux) 4210 { 4211 GstMapInfo mfro_map = GST_MAP_INFO_INIT; 4212 GstMapInfo mfra_map = GST_MAP_INFO_INIT; 4213 GstBuffer *mfro = NULL, *mfra = NULL; 4214 GstFlowReturn flow; 4215 gboolean ret = FALSE; 4216 GNode *mfra_node, *tfra_node; 4217 guint64 mfra_offset = 0; 4218 guint32 fourcc, mfra_size; 4219 gint64 len; 4220 4221 /* query upstream size in bytes */ 4222 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len)) 4223 goto size_query_failed; 4224 4225 /* mfro box should be at the very end of the file */ 4226 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro); 4227 if (flow != GST_FLOW_OK) 4228 goto exit; 4229 4230 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ); 4231 4232 fourcc = QT_FOURCC (mfro_map.data + 4); 4233 if (fourcc != FOURCC_mfro) 4234 goto exit; 4235 4236 GST_INFO_OBJECT (qtdemux, "Found mfro box"); 4237 if (mfro_map.size < 16) 4238 goto invalid_mfro_size; 4239 4240 mfra_size = QT_UINT32 (mfro_map.data + 12); 4241 if (mfra_size >= len) 4242 goto invalid_mfra_size; 4243 4244 mfra_offset = len - mfra_size; 4245 4246 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u", 4247 mfra_offset, mfra_size); 4248 4249 /* now get and parse mfra box */ 4250 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra); 4251 if (flow != GST_FLOW_OK) 4252 goto broken_file; 4253 4254 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ); 4255 4256 mfra_node = g_node_new ((guint8 *) mfra_map.data); 4257 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size); 4258 4259 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra); 4260 4261 while (tfra_node) { 4262 qtdemux_parse_tfra (qtdemux, tfra_node); 4263 /* iterate all siblings */ 4264 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra); 4265 } 4266 g_node_destroy (mfra_node); 4267 4268 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)"); 4269 ret = TRUE; 4270 4271 exit: 4272 4273 if (mfro) { 4274 if (mfro_map.memory != NULL) 4275 gst_buffer_unmap (mfro, &mfro_map); 4276 gst_buffer_unref (mfro); 4277 } 4278 if (mfra) { 4279 if (mfra_map.memory != NULL) 4280 gst_buffer_unmap (mfra, &mfra_map); 4281 gst_buffer_unref (mfra); 4282 } 4283 return ret; 4284 4285 /* ERRORS */ 4286 size_query_failed: 4287 { 4288 GST_WARNING_OBJECT (qtdemux, "could not query upstream size"); 4289 goto exit; 4290 } 4291 invalid_mfro_size: 4292 { 4293 GST_WARNING_OBJECT (qtdemux, "mfro size is too small"); 4294 goto exit; 4295 } 4296 invalid_mfra_size: 4297 { 4298 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid"); 4299 goto exit; 4300 } 4301 broken_file: 4302 { 4303 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file"); 4304 goto exit; 4305 } 4306 } 4307 4308 static guint64 4309 add_offset (guint64 offset, guint64 advance) 4310 { 4311 /* Avoid 64-bit overflow by clamping */ 4312 if (offset > G_MAXUINT64 - advance) 4313 return G_MAXUINT64; 4314 return offset + advance; 4315 } 4316 4317 static GstFlowReturn 4318 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux) 4319 { 4320 guint64 length = 0; 4321 guint32 fourcc = 0; 4322 GstBuffer *buf = NULL; 4323 GstFlowReturn ret = GST_FLOW_OK; 4324 guint64 cur_offset = qtdemux->offset; 4325 GstMapInfo map; 4326 4327 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf); 4328 if (G_UNLIKELY (ret != GST_FLOW_OK)) 4329 goto beach; 4330 gst_buffer_map (buf, &map, GST_MAP_READ); 4331 if (G_LIKELY (map.size >= 8)) 4332 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc); 4333 gst_buffer_unmap (buf, &map); 4334 gst_buffer_unref (buf); 4335 4336 /* maybe we already got most we needed, so only consider this eof */ 4337 if (G_UNLIKELY (length == 0)) { 4338 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX, 4339 (_("Invalid atom size.")), 4340 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length", 4341 GST_FOURCC_ARGS (fourcc))); 4342 ret = GST_FLOW_EOS; 4343 goto beach; 4344 } 4345 4346 switch (fourcc) { 4347 case FOURCC_moof: 4348 /* record for later parsing when needed */ 4349 if (!qtdemux->moof_offset) { 4350 qtdemux->moof_offset = qtdemux->offset; 4351 } 4352 if (qtdemux_pull_mfro_mfra (qtdemux)) { 4353 /* FIXME */ 4354 } else { 4355 qtdemux->offset += length; /* skip moof and keep going */ 4356 } 4357 if (qtdemux->got_moov) { 4358 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers"); 4359 ret = GST_FLOW_EOS; 4360 goto beach; 4361 } 4362 break; 4363 case FOURCC_mdat: 4364 case FOURCC_free: 4365 case FOURCC_skip: 4366 case FOURCC_wide: 4367 case FOURCC_PICT: 4368 case FOURCC_pnot: 4369 { 4370 GST_LOG_OBJECT (qtdemux, 4371 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT, 4372 GST_FOURCC_ARGS (fourcc), cur_offset); 4373 qtdemux->offset = add_offset (qtdemux->offset, length); 4374 break; 4375 } 4376 case FOURCC_moov: 4377 { 4378 GstBuffer *moov = NULL; 4379 4380 if (qtdemux->got_moov) { 4381 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already"); 4382 qtdemux->offset = add_offset (qtdemux->offset, length); 4383 goto beach; 4384 } 4385 4386 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov); 4387 if (ret != GST_FLOW_OK) 4388 goto beach; 4389 gst_buffer_map (moov, &map, GST_MAP_READ); 4390 4391 if (length != map.size) { 4392 /* Some files have a 'moov' atom at the end of the file which contains 4393 * a terminal 'free' atom where the body of the atom is missing. 4394 * Check for, and permit, this special case. 4395 */ 4396 if (map.size >= 8) { 4397 guint8 *final_data = map.data + (map.size - 8); 4398 guint32 final_length = QT_UINT32 (final_data); 4399 guint32 final_fourcc = QT_FOURCC (final_data + 4); 4400 4401 if (final_fourcc == FOURCC_free 4402 && map.size + final_length - 8 == length) { 4403 /* Ok, we've found that special case. Allocate a new buffer with 4404 * that free atom actually present. */ 4405 GstBuffer *newmoov = gst_buffer_new_and_alloc (length); 4406 gst_buffer_fill (newmoov, 0, map.data, map.size); 4407 gst_buffer_memset (newmoov, map.size, 0, final_length - 8); 4408 gst_buffer_unmap (moov, &map); 4409 gst_buffer_unref (moov); 4410 moov = newmoov; 4411 gst_buffer_map (moov, &map, GST_MAP_READ); 4412 } 4413 } 4414 } 4415 4416 if (length != map.size) { 4417 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX, 4418 (_("This file is incomplete and cannot be played.")), 4419 ("We got less than expected (received %" G_GSIZE_FORMAT 4420 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size, 4421 (guint) length, cur_offset)); 4422 gst_buffer_unmap (moov, &map); 4423 gst_buffer_unref (moov); 4424 ret = GST_FLOW_ERROR; 4425 goto beach; 4426 } 4427 qtdemux->offset += length; 4428 4429 qtdemux_parse_moov (qtdemux, map.data, length); 4430 qtdemux_node_dump (qtdemux, qtdemux->moov_node); 4431 4432 #ifdef GSTREAMER_LITE 4433 if (!qtdemux_parse_tree (qtdemux)) { 4434 ret = GST_FLOW_ERROR; 4435 break; 4436 } 4437 #else 4438 qtdemux_parse_tree (qtdemux); 4439 #endif //GSTREAMER_LITE 4440 4441 if (qtdemux->moov_node_compressed) { 4442 g_node_destroy (qtdemux->moov_node_compressed); 4443 g_free (qtdemux->moov_node->data); 4444 } 4445 qtdemux->moov_node_compressed = NULL; 4446 g_node_destroy (qtdemux->moov_node); 4447 qtdemux->moov_node = NULL; 4448 gst_buffer_unmap (moov, &map); 4449 gst_buffer_unref (moov); 4450 qtdemux->got_moov = TRUE; 4451 4452 break; 4453 } 4454 case FOURCC_ftyp: 4455 { 4456 GstBuffer *ftyp = NULL; 4457 4458 /* extract major brand; might come in handy for ISO vs QT issues */ 4459 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp); 4460 if (ret != GST_FLOW_OK) 4461 goto beach; 4462 qtdemux->offset += length; 4463 gst_buffer_map (ftyp, &map, GST_MAP_READ); 4464 qtdemux_parse_ftyp (qtdemux, map.data, map.size); 4465 gst_buffer_unmap (ftyp, &map); 4466 gst_buffer_unref (ftyp); 4467 break; 4468 } 4469 case FOURCC_uuid: 4470 { 4471 GstBuffer *uuid = NULL; 4472 4473 /* uuid are extension atoms */ 4474 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid); 4475 if (ret != GST_FLOW_OK) 4476 goto beach; 4477 qtdemux->offset += length; 4478 gst_buffer_map (uuid, &map, GST_MAP_READ); 4479 qtdemux_parse_uuid (qtdemux, map.data, map.size); 4480 gst_buffer_unmap (uuid, &map); 4481 gst_buffer_unref (uuid); 4482 break; 4483 } 4484 case FOURCC_sidx: 4485 { 4486 GstBuffer *sidx = NULL; 4487 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx); 4488 if (ret != GST_FLOW_OK) 4489 goto beach; 4490 qtdemux->offset += length; 4491 gst_buffer_map (sidx, &map, GST_MAP_READ); 4492 qtdemux_parse_sidx (qtdemux, map.data, map.size); 4493 gst_buffer_unmap (sidx, &map); 4494 gst_buffer_unref (sidx); 4495 break; 4496 } 4497 default: 4498 { 4499 GstBuffer *unknown = NULL; 4500 4501 GST_LOG_OBJECT (qtdemux, 4502 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT 4503 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length, 4504 cur_offset); 4505 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown); 4506 if (ret != GST_FLOW_OK) 4507 goto beach; 4508 gst_buffer_map (unknown, &map, GST_MAP_READ); 4509 GST_MEMDUMP ("Unknown tag", map.data, map.size); 4510 gst_buffer_unmap (unknown, &map); 4511 gst_buffer_unref (unknown); 4512 qtdemux->offset += length; 4513 break; 4514 } 4515 } 4516 4517 beach: 4518 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) { 4519 /* digested all data, show what we have */ 4520 qtdemux_prepare_streams (qtdemux); 4521 ret = qtdemux_expose_streams (qtdemux); 4522 4523 qtdemux->state = QTDEMUX_STATE_MOVIE; 4524 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)", 4525 qtdemux->state); 4526 return ret; 4527 } 4528 return ret; 4529 } 4530 4531 /* Seeks to the previous keyframe of the indexed stream and 4532 * aligns other streams with respect to the keyframe timestamp 4533 * of indexed stream. Only called in case of Reverse Playback 4534 */ 4535 static GstFlowReturn 4536 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux) 4537 { 4538 guint8 n = 0; 4539 guint32 seg_idx = 0, k_index = 0; 4540 guint32 ref_seg_idx, ref_k_index; 4541 GstClockTime k_pos = 0, last_stop = 0; 4542 QtDemuxSegment *seg = NULL; 4543 QtDemuxStream *ref_str = NULL; 4544 guint64 seg_media_start_mov; /* segment media start time in mov format */ 4545 guint64 target_ts; 4546 4547 /* Now we choose an arbitrary stream, get the previous keyframe timestamp 4548 * and finally align all the other streams on that timestamp with their 4549 * respective keyframes */ 4550 for (n = 0; n < qtdemux->n_streams; n++) { 4551 QtDemuxStream *str = qtdemux->streams[n]; 4552 4553 /* No candidate yet, take the first stream */ 4554 if (!ref_str) { 4555 ref_str = str; 4556 continue; 4557 } 4558 4559 /* So that stream has a segment, we prefer video streams */ 4560 if (str->subtype == FOURCC_vide) { 4561 ref_str = str; 4562 break; 4563 } 4564 } 4565 4566 if (G_UNLIKELY (!ref_str)) { 4567 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream"); 4568 goto eos; 4569 } 4570 4571 if (G_UNLIKELY (!ref_str->from_sample)) { 4572 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file"); 4573 goto eos; 4574 } 4575 4576 /* So that stream has been playing from from_sample to to_sample. We will 4577 * get the timestamp of the previous sample and search for a keyframe before 4578 * that. For audio streams we do an arbitrary jump in the past (10 samples) */ 4579 if (ref_str->subtype == FOURCC_vide) { 4580 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str, 4581 ref_str->from_sample - 1, FALSE); 4582 } else { 4583 if (ref_str->from_sample >= 10) 4584 k_index = ref_str->from_sample - 10; 4585 else 4586 k_index = 0; 4587 } 4588 4589 target_ts = 4590 ref_str->samples[k_index].timestamp + 4591 ref_str->samples[k_index].pts_offset; 4592 4593 /* get current segment for that stream */ 4594 seg = &ref_str->segments[ref_str->segment_index]; 4595 /* Use segment start in original timescale for comparisons */ 4596 seg_media_start_mov = seg->trak_media_start; 4597 4598 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT 4599 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n", 4600 k_index, target_ts, seg_media_start_mov, 4601 GST_TIME_ARGS (seg->media_start)); 4602 4603 /* Crawl back through segments to find the one containing this I frame */ 4604 while (target_ts < seg_media_start_mov) { 4605 GST_DEBUG_OBJECT (qtdemux, 4606 "keyframe position (sample %u) is out of segment %u " " target %" 4607 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index, 4608 ref_str->segment_index, target_ts, seg_media_start_mov); 4609 4610 if (G_UNLIKELY (!ref_str->segment_index)) { 4611 /* Reached first segment, let's consider it's EOS */ 4612 goto eos; 4613 } 4614 ref_str->segment_index--; 4615 seg = &ref_str->segments[ref_str->segment_index]; 4616 /* Use segment start in original timescale for comparisons */ 4617 seg_media_start_mov = seg->trak_media_start; 4618 } 4619 /* Calculate time position of the keyframe and where we should stop */ 4620 k_pos = 4621 QTSTREAMTIME_TO_GSTTIME (ref_str, 4622 target_ts - seg->trak_media_start) + seg->time; 4623 last_stop = 4624 QTSTREAMTIME_TO_GSTTIME (ref_str, 4625 ref_str->samples[ref_str->from_sample].timestamp - 4626 seg->trak_media_start) + seg->time; 4627 4628 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, " 4629 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample, 4630 k_index, GST_TIME_ARGS (k_pos)); 4631 4632 /* Set last_stop with the keyframe timestamp we pushed of that stream */ 4633 qtdemux->segment.position = last_stop; 4634 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT, 4635 GST_TIME_ARGS (last_stop)); 4636 4637 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) { 4638 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment"); 4639 goto eos; 4640 } 4641 4642 ref_seg_idx = ref_str->segment_index; 4643 ref_k_index = k_index; 4644 4645 /* Align them all on this */ 4646 for (n = 0; n < qtdemux->n_streams; n++) { 4647 guint32 index = 0; 4648 GstClockTime seg_time = 0; 4649 QtDemuxStream *str = qtdemux->streams[n]; 4650 4651 /* aligning reference stream again might lead to backing up to yet another 4652 * keyframe (due to timestamp rounding issues), 4653 * potentially putting more load on downstream; so let's try to avoid */ 4654 if (str == ref_str) { 4655 seg_idx = ref_seg_idx; 4656 seg = &str->segments[seg_idx]; 4657 k_index = ref_k_index; 4658 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, " 4659 "sample at index %d", n, ref_str->segment_index, k_index); 4660 } else { 4661 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos); 4662 GST_DEBUG_OBJECT (qtdemux, 4663 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n, 4664 seg_idx, GST_TIME_ARGS (k_pos)); 4665 4666 /* get segment and time in the segment */ 4667 seg = &str->segments[seg_idx]; 4668 seg_time = k_pos - seg->time; 4669 4670 /* get the media time in the segment. 4671 * No adjustment for empty "filler" segments */ 4672 if (seg->media_start != GST_CLOCK_TIME_NONE) 4673 seg_time += seg->media_start; 4674 4675 /* get the index of the sample with media time */ 4676 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time); 4677 GST_DEBUG_OBJECT (qtdemux, 4678 "stream %d sample for %" GST_TIME_FORMAT " at %u", n, 4679 GST_TIME_ARGS (seg_time), index); 4680 4681 /* find previous keyframe */ 4682 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE); 4683 } 4684 4685 /* Remember until where we want to go */ 4686 str->to_sample = str->from_sample - 1; 4687 /* Define our time position */ 4688 target_ts = 4689 str->samples[k_index].timestamp + str->samples[k_index].pts_offset; 4690 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time; 4691 if (seg->media_start != GST_CLOCK_TIME_NONE) 4692 str->time_position -= seg->media_start; 4693 4694 /* Now seek back in time */ 4695 gst_qtdemux_move_stream (qtdemux, str, k_index); 4696 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %" 4697 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index, 4698 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample); 4699 } 4700 4701 return GST_FLOW_OK; 4702 4703 eos: 4704 return GST_FLOW_EOS; 4705 } 4706 4707 /* 4708 * Gets the current qt segment start, stop and position for the 4709 * given time offset. This is used in update_segment() 4710 */ 4711 static void 4712 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux, 4713 QtDemuxStream * stream, GstClockTime offset, 4714 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time) 4715 { 4716 GstClockTime seg_time; 4717 GstClockTime start, stop, time; 4718 QtDemuxSegment *segment; 4719 4720 segment = &stream->segments[stream->segment_index]; 4721 4722 /* get time in this segment */ 4723 seg_time = (offset - segment->time) * segment->rate; 4724 4725 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT, 4726 GST_TIME_ARGS (seg_time)); 4727 4728 if (G_UNLIKELY (seg_time > segment->duration)) { 4729 GST_LOG_OBJECT (stream->pad, 4730 "seg_time > segment->duration %" GST_TIME_FORMAT, 4731 GST_TIME_ARGS (segment->duration)); 4732 seg_time = segment->duration; 4733 } 4734 4735 /* qtdemux->segment.stop is in outside-time-realm, whereas 4736 * segment->media_stop is in track-time-realm. 4737 * 4738 * In order to compare the two, we need to bring segment.stop 4739 * into the track-time-realm 4740 * 4741 * FIXME - does this comment still hold? Don't see any conversion here */ 4742 4743 stop = qtdemux->segment.stop; 4744 if (stop == GST_CLOCK_TIME_NONE) 4745 stop = qtdemux->segment.duration; 4746 if (stop == GST_CLOCK_TIME_NONE) 4747 stop = segment->media_stop; 4748 else 4749 stop = 4750 MIN (segment->media_stop, stop - segment->time + segment->media_start); 4751 4752 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) { 4753 start = segment->time + seg_time; 4754 time = offset; 4755 stop = start - seg_time + segment->duration; 4756 } else if (qtdemux->segment.rate >= 0) { 4757 start = MIN (segment->media_start + seg_time, stop); 4758 time = offset; 4759 } else { 4760 if (segment->media_start >= qtdemux->segment.start) { 4761 time = segment->time; 4762 } else { 4763 time = segment->time + (qtdemux->segment.start - segment->media_start); 4764 } 4765 4766 start = MAX (segment->media_start, qtdemux->segment.start); 4767 stop = MIN (segment->media_start + seg_time, stop); 4768 } 4769 4770 *_start = start; 4771 *_stop = stop; 4772 *_time = time; 4773 } 4774 4775 /* 4776 * Updates the qt segment used for the stream and pushes a new segment event 4777 * downstream on this stream's pad. 4778 */ 4779 static gboolean 4780 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream, 4781 gint seg_idx, GstClockTime offset, GstClockTime * _start, 4782 GstClockTime * _stop) 4783 { 4784 QtDemuxSegment *segment; 4785 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0; 4786 gdouble rate; 4787 GstEvent *event; 4788 4789 /* update the current segment */ 4790 stream->segment_index = seg_idx; 4791 4792 /* get the segment */ 4793 segment = &stream->segments[seg_idx]; 4794 4795 if (G_UNLIKELY (offset < segment->time)) { 4796 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT, 4797 GST_TIME_ARGS (segment->time)); 4798 return FALSE; 4799 } 4800 4801 /* segment lies beyond total indicated duration */ 4802 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE && 4803 segment->time > qtdemux->segment.duration)) { 4804 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT 4805 " < segment->time %" GST_TIME_FORMAT, 4806 GST_TIME_ARGS (qtdemux->segment.duration), 4807 GST_TIME_ARGS (segment->time)); 4808 return FALSE; 4809 } 4810 4811 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset, 4812 &start, &stop, &time); 4813 4814 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT 4815 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx, 4816 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time)); 4817 4818 /* combine global rate with that of the segment */ 4819 rate = segment->rate * qtdemux->segment.rate; 4820 4821 /* Copy flags from main segment */ 4822 stream->segment.flags = qtdemux->segment.flags; 4823 4824 /* update the segment values used for clipping */ 4825 stream->segment.offset = qtdemux->segment.offset; 4826 stream->segment.base = qtdemux->segment.base + stream->accumulated_base; 4827 stream->segment.applied_rate = qtdemux->segment.applied_rate; 4828 stream->segment.rate = rate; 4829 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream, 4830 stream->cslg_shift); 4831 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream, 4832 stream->cslg_shift); 4833 stream->segment.time = time; 4834 stream->segment.position = stream->segment.start; 4835 4836 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT, 4837 &stream->segment); 4838 4839 /* now prepare and send the segment */ 4840 if (stream->pad) { 4841 event = gst_event_new_segment (&stream->segment); 4842 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) { 4843 gst_event_set_seqnum (event, qtdemux->segment_seqnum); 4844 } 4845 gst_pad_push_event (stream->pad, event); 4846 /* assume we can send more data now */ 4847 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK; 4848 /* clear to send tags on this pad now */ 4849 gst_qtdemux_push_tags (qtdemux, stream); 4850 } 4851 4852 if (_start) 4853 *_start = start; 4854 if (_stop) 4855 *_stop = stop; 4856 4857 return TRUE; 4858 } 4859 4860 /* activate the given segment number @seg_idx of @stream at time @offset. 4861 * @offset is an absolute global position over all the segments. 4862 * 4863 * This will push out a NEWSEGMENT event with the right values and 4864 * position the stream index to the first decodable sample before 4865 * @offset. 4866 */ 4867 static gboolean 4868 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream, 4869 guint32 seg_idx, GstClockTime offset) 4870 { 4871 QtDemuxSegment *segment; 4872 guint32 index, kf_index; 4873 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE; 4874 4875 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT, 4876 seg_idx, GST_TIME_ARGS (offset)); 4877 4878 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset, 4879 &start, &stop)) 4880 return FALSE; 4881 4882 segment = &stream->segments[stream->segment_index]; 4883 4884 /* in the fragmented case, we pick a fragment that starts before our 4885 * desired position and rely on downstream to wait for a keyframe 4886 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the 4887 * tfra entries tells us which trun/sample the key unit is in, but we don't 4888 * make use of this additional information at the moment) */ 4889 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) { 4890 stream->to_sample = G_MAXUINT32; 4891 return TRUE; 4892 } else { 4893 /* well, it will be taken care of below */ 4894 qtdemux->fragmented_seek_pending = FALSE; 4895 /* FIXME ideally the do_fragmented_seek can be done right here, 4896 * rather than at loop level 4897 * (which might even allow handling edit lists in a fragmented file) */ 4898 } 4899 4900 /* We don't need to look for a sample in push-based */ 4901 if (!qtdemux->pullbased) 4902 return TRUE; 4903 4904 /* and move to the keyframe before the indicated media time of the 4905 * segment */ 4906 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) { 4907 if (qtdemux->segment.rate >= 0) { 4908 index = gst_qtdemux_find_index_linear (qtdemux, stream, start); 4909 stream->to_sample = G_MAXUINT32; 4910 GST_DEBUG_OBJECT (stream->pad, 4911 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %" 4912 GST_TIME_FORMAT, GST_TIME_ARGS (start), index, 4913 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index]))); 4914 } else { 4915 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop); 4916 stream->to_sample = index; 4917 GST_DEBUG_OBJECT (stream->pad, 4918 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %" 4919 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index, 4920 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index]))); 4921 } 4922 } else { 4923 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, " 4924 "this is an empty segment"); 4925 return TRUE; 4926 } 4927 4928 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear () 4929 * encountered an error and printed a message so we return appropriately */ 4930 if (index == -1) 4931 return FALSE; 4932 4933 /* we're at the right spot */ 4934 if (index == stream->sample_index) { 4935 GST_DEBUG_OBJECT (stream->pad, "we are at the right index"); 4936 return TRUE; 4937 } 4938 4939 /* find keyframe of the target index */ 4940 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE); 4941 4942 /* *INDENT-OFF* */ 4943 /* indent does stupid stuff with stream->samples[].timestamp */ 4944 4945 /* if we move forwards, we don't have to go back to the previous 4946 * keyframe since we already sent that. We can also just jump to 4947 * the keyframe right before the target index if there is one. */ 4948 if (index > stream->sample_index) { 4949 /* moving forwards check if we move past a keyframe */ 4950 if (kf_index > stream->sample_index) { 4951 GST_DEBUG_OBJECT (stream->pad, 4952 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index, 4953 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])), 4954 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index]))); 4955 gst_qtdemux_move_stream (qtdemux, stream, kf_index); 4956 } else { 4957 GST_DEBUG_OBJECT (stream->pad, 4958 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index, 4959 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])), 4960 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index]))); 4961 } 4962 } else { 4963 GST_DEBUG_OBJECT (stream->pad, 4964 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index, 4965 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])), 4966 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index]))); 4967 gst_qtdemux_move_stream (qtdemux, stream, kf_index); 4968 } 4969 4970 /* *INDENT-ON* */ 4971 4972 return TRUE; 4973 } 4974 4975 /* prepare to get the current sample of @stream, getting essential values. 4976 * 4977 * This function will also prepare and send the segment when needed. 4978 * 4979 * Return FALSE if the stream is EOS. 4980 * 4981 * PULL-BASED 4982 */ 4983 static gboolean 4984 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux, 4985 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size, 4986 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration, 4987 gboolean * keyframe) 4988 { 4989 QtDemuxSample *sample; 4990 GstClockTime time_position; 4991 guint32 seg_idx; 4992 4993 g_return_val_if_fail (stream != NULL, FALSE); 4994 4995 time_position = stream->time_position; 4996 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE)) 4997 goto eos; 4998 4999 seg_idx = stream->segment_index; 5000 if (G_UNLIKELY (seg_idx == -1)) { 5001 /* find segment corresponding to time_position if we are looking 5002 * for a segment. */ 5003 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position); 5004 } 5005 5006 /* different segment, activate it, sample_index will be set. */ 5007 if (G_UNLIKELY (stream->segment_index != seg_idx)) 5008 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position); 5009 5010 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream-> 5011 segment_index]))) { 5012 QtDemuxSegment *seg = &stream->segments[stream->segment_index]; 5013 5014 GST_LOG_OBJECT (qtdemux, "Empty segment activated," 5015 " prepare empty sample"); 5016 5017 *empty = TRUE; 5018 *pts = *dts = time_position; 5019 *duration = seg->duration - (time_position - seg->time); 5020 5021 return TRUE; 5022 } 5023 5024 *empty = FALSE; 5025 5026 if (stream->sample_index == -1) 5027 stream->sample_index = 0; 5028 5029 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u", 5030 stream->sample_index, stream->n_samples); 5031 5032 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) { 5033 if (!qtdemux->fragmented) 5034 goto eos; 5035 5036 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more"); 5037 do { 5038 GstFlowReturn flow; 5039 5040 GST_OBJECT_LOCK (qtdemux); 5041 flow = qtdemux_add_fragmented_samples (qtdemux); 5042 GST_OBJECT_UNLOCK (qtdemux); 5043 5044 if (flow != GST_FLOW_OK) 5045 goto eos; 5046 } 5047 while (stream->sample_index >= stream->n_samples); 5048 } 5049 5050 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) { 5051 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", 5052 stream->sample_index); 5053 return FALSE; 5054 } 5055 5056 /* now get the info for the sample we're at */ 5057 sample = &stream->samples[stream->sample_index]; 5058 5059 *dts = QTSAMPLE_DTS (stream, sample); 5060 *pts = QTSAMPLE_PTS (stream, sample); 5061 *offset = sample->offset; 5062 *size = sample->size; 5063 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts); 5064 *keyframe = QTSAMPLE_KEYFRAME (stream, sample); 5065 5066 return TRUE; 5067 5068 /* special cases */ 5069 eos: 5070 { 5071 stream->time_position = GST_CLOCK_TIME_NONE; 5072 return FALSE; 5073 } 5074 } 5075 5076 /* move to the next sample in @stream. 5077 * 5078 * Moves to the next segment when needed. 5079 */ 5080 static void 5081 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream) 5082 { 5083 QtDemuxSample *sample; 5084 QtDemuxSegment *segment; 5085 5086 /* get current segment */ 5087 segment = &stream->segments[stream->segment_index]; 5088 5089 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) { 5090 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance"); 5091 goto next_segment; 5092 } 5093 5094 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) { 5095 /* Mark the stream as EOS */ 5096 GST_DEBUG_OBJECT (qtdemux, 5097 "reached max allowed sample %u, mark EOS", stream->to_sample); 5098 stream->time_position = GST_CLOCK_TIME_NONE; 5099 return; 5100 } 5101 5102 /* move to next sample */ 5103 stream->sample_index++; 5104 stream->offset_in_sample = 0; 5105 5106 /* reached the last sample, we need the next segment */ 5107 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) 5108 goto next_segment; 5109 5110 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) { 5111 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", 5112 stream->sample_index); 5113 return; 5114 } 5115 5116 /* get next sample */ 5117 sample = &stream->samples[stream->sample_index]; 5118 5119 /* see if we are past the segment */ 5120 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop)) 5121 goto next_segment; 5122 5123 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) { 5124 /* inside the segment, update time_position, looks very familiar to 5125 * GStreamer segments, doesn't it? */ 5126 stream->time_position = 5127 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time; 5128 } else { 5129 /* not yet in segment, time does not yet increment. This means 5130 * that we are still prerolling keyframes to the decoder so it can 5131 * decode the first sample of the segment. */ 5132 stream->time_position = segment->time; 5133 } 5134 return; 5135 5136 /* move to the next segment */ 5137 next_segment: 5138 { 5139 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index); 5140 5141 if (stream->segment_index == stream->n_segments - 1) { 5142 /* are we at the end of the last segment, we're EOS */ 5143 stream->time_position = GST_CLOCK_TIME_NONE; 5144 } else { 5145 /* else we're only at the end of the current segment */ 5146 stream->time_position = segment->stop_time; 5147 } 5148 /* make sure we select a new segment */ 5149 5150 /* accumulate previous segments */ 5151 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop)) 5152 stream->accumulated_base += 5153 (stream->segment.stop - 5154 stream->segment.start) / ABS (stream->segment.rate); 5155 5156 stream->segment_index = -1; 5157 } 5158 } 5159 5160 static void 5161 gst_qtdemux_sync_streams (GstQTDemux * demux) 5162 { 5163 gint i; 5164 5165 if (demux->n_streams <= 1) 5166 return; 5167 5168 for (i = 0; i < demux->n_streams; i++) { 5169 QtDemuxStream *stream; 5170 GstClockTime end_time; 5171 5172 stream = demux->streams[i]; 5173 5174 if (!stream->pad) 5175 continue; 5176 5177 /* TODO advance time on subtitle streams here, if any some day */ 5178 5179 /* some clips/trailers may have unbalanced streams at the end, 5180 * so send EOS on shorter stream to prevent stalling others */ 5181 5182 /* do not mess with EOS if SEGMENT seeking */ 5183 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) 5184 continue; 5185 5186 if (demux->pullbased) { 5187 /* loop mode is sample time based */ 5188 if (!STREAM_IS_EOS (stream)) 5189 continue; 5190 } else { 5191 /* push mode is byte position based */ 5192 if (stream->n_samples && 5193 stream->samples[stream->n_samples - 1].offset >= demux->offset) 5194 continue; 5195 } 5196 5197 if (stream->sent_eos) 5198 continue; 5199 5200 /* only act if some gap */ 5201 end_time = stream->segments[stream->n_segments - 1].stop_time; 5202 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT 5203 ", stream end: %" GST_TIME_FORMAT, 5204 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time)); 5205 if (GST_CLOCK_TIME_IS_VALID (end_time) 5206 && (end_time + 2 * GST_SECOND < demux->segment.position)) { 5207 GstEvent *event; 5208 5209 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s", 5210 GST_PAD_NAME (stream->pad)); 5211 stream->sent_eos = TRUE; 5212 event = gst_event_new_eos (); 5213 if (demux->segment_seqnum != GST_SEQNUM_INVALID) 5214 gst_event_set_seqnum (event, demux->segment_seqnum); 5215 gst_pad_push_event (stream->pad, event); 5216 } 5217 } 5218 } 5219 5220 /* EOS and NOT_LINKED need to be combined. This means that we return: 5221 * 5222 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED. 5223 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED. 5224 */ 5225 static GstFlowReturn 5226 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream, 5227 GstFlowReturn ret) 5228 { 5229 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret)); 5230 5231 if (stream->pad) 5232 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad, 5233 ret); 5234 else 5235 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret); 5236 5237 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret)); 5238 return ret; 5239 } 5240 5241 /* the input buffer metadata must be writable. Returns NULL when the buffer is 5242 * completely clipped 5243 * 5244 * Should be used only with raw buffers */ 5245 static GstBuffer * 5246 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream, 5247 GstBuffer * buf) 5248 { 5249 guint64 start, stop, cstart, cstop, diff; 5250 GstClockTime pts, duration; 5251 gsize size, osize; 5252 gint num_rate, denom_rate; 5253 gint frame_size; 5254 gboolean clip_data; 5255 guint offset; 5256 5257 osize = size = gst_buffer_get_size (buf); 5258 offset = 0; 5259 5260 /* depending on the type, setup the clip parameters */ 5261 if (stream->subtype == FOURCC_soun) { 5262 frame_size = CUR_STREAM (stream)->bytes_per_frame; 5263 num_rate = GST_SECOND; 5264 denom_rate = (gint) CUR_STREAM (stream)->rate; 5265 clip_data = TRUE; 5266 } else if (stream->subtype == FOURCC_vide) { 5267 frame_size = size; 5268 num_rate = CUR_STREAM (stream)->fps_n; 5269 denom_rate = CUR_STREAM (stream)->fps_d; 5270 clip_data = FALSE; 5271 } else 5272 goto wrong_type; 5273 5274 if (frame_size <= 0) 5275 goto bad_frame_size; 5276 5277 /* we can only clip if we have a valid pts */ 5278 pts = GST_BUFFER_PTS (buf); 5279 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts))) 5280 goto no_pts; 5281 5282 duration = GST_BUFFER_DURATION (buf); 5283 5284 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) { 5285 duration = 5286 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate); 5287 } 5288 5289 start = pts; 5290 stop = start + duration; 5291 5292 if (G_UNLIKELY (!gst_segment_clip (&stream->segment, 5293 GST_FORMAT_TIME, start, stop, &cstart, &cstop))) 5294 goto clipped; 5295 5296 /* see if some clipping happened */ 5297 diff = cstart - start; 5298 if (diff > 0) { 5299 pts += diff; 5300 duration -= diff; 5301 5302 if (clip_data) { 5303 /* bring clipped time to samples and to bytes */ 5304 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate); 5305 diff *= frame_size; 5306 5307 GST_DEBUG_OBJECT (qtdemux, 5308 "clipping start to %" GST_TIME_FORMAT " %" 5309 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff); 5310 5311 offset = diff; 5312 size -= diff; 5313 } 5314 } 5315 diff = stop - cstop; 5316 if (diff > 0) { 5317 duration -= diff; 5318 5319 if (clip_data) { 5320 /* bring clipped time to samples and then to bytes */ 5321 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate); 5322 diff *= frame_size; 5323 GST_DEBUG_OBJECT (qtdemux, 5324 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT 5325 " bytes", GST_TIME_ARGS (cstop), diff); 5326 size -= diff; 5327 } 5328 } 5329 5330 if (offset != 0 || size != osize) 5331 gst_buffer_resize (buf, offset, size); 5332 5333 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE; 5334 GST_BUFFER_PTS (buf) = pts; 5335 GST_BUFFER_DURATION (buf) = duration; 5336 5337 return buf; 5338 5339 /* dropped buffer */ 5340 wrong_type: 5341 { 5342 GST_DEBUG_OBJECT (qtdemux, "unknown stream type"); 5343 return buf; 5344 } 5345 bad_frame_size: 5346 { 5347 GST_DEBUG_OBJECT (qtdemux, "bad frame size"); 5348 return buf; 5349 } 5350 no_pts: 5351 { 5352 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer"); 5353 return buf; 5354 } 5355 clipped: 5356 { 5357 GST_DEBUG_OBJECT (qtdemux, "clipped buffer"); 5358 gst_buffer_unref (buf); 5359 return NULL; 5360 } 5361 } 5362 5363 static GstBuffer * 5364 gst_qtdemux_align_buffer (GstQTDemux * demux, 5365 GstBuffer * buffer, gsize alignment) 5366 { 5367 GstMapInfo map; 5368 5369 gst_buffer_map (buffer, &map, GST_MAP_READ); 5370 5371 if (map.size < sizeof (guintptr)) { 5372 gst_buffer_unmap (buffer, &map); 5373 return buffer; 5374 } 5375 5376 if (((guintptr) map.data) & (alignment - 1)) { 5377 GstBuffer *new_buffer; 5378 GstAllocationParams params = { 0, alignment - 1, 0, 0, }; 5379 5380 new_buffer = gst_buffer_new_allocate (NULL, 5381 gst_buffer_get_size (buffer), ¶ms); 5382 5383 /* Copy data "by hand", so ensure alignment is kept: */ 5384 gst_buffer_fill (new_buffer, 0, map.data, map.size); 5385 5386 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1); 5387 GST_DEBUG_OBJECT (demux, 5388 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated", 5389 alignment); 5390 5391 gst_buffer_unmap (buffer, &map); 5392 gst_buffer_unref (buffer); 5393 5394 return new_buffer; 5395 } 5396 5397 gst_buffer_unmap (buffer, &map); 5398 return buffer; 5399 } 5400 5401 /* the input buffer metadata must be writable, 5402 * but time/duration etc not yet set and need not be preserved */ 5403 static GstBuffer * 5404 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream, 5405 GstBuffer * buf) 5406 { 5407 GstMapInfo map; 5408 guint nsize = 0; 5409 gchar *str; 5410 5411 /* not many cases for now */ 5412 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) { 5413 /* send a one time dvd clut event */ 5414 if (stream->pending_event && stream->pad) 5415 gst_pad_push_event (stream->pad, stream->pending_event); 5416 stream->pending_event = NULL; 5417 } 5418 5419 if (G_UNLIKELY (stream->subtype != FOURCC_text 5420 && stream->subtype != FOURCC_sbtl && 5421 stream->subtype != FOURCC_subp)) { 5422 return buf; 5423 } 5424 5425 gst_buffer_map (buf, &map, GST_MAP_READ); 5426 5427 /* empty buffer is sent to terminate previous subtitle */ 5428 if (map.size <= 2) { 5429 gst_buffer_unmap (buf, &map); 5430 gst_buffer_unref (buf); 5431 return NULL; 5432 } 5433 if (stream->subtype == FOURCC_subp) { 5434 /* That's all the processing needed for subpictures */ 5435 gst_buffer_unmap (buf, &map); 5436 return buf; 5437 } 5438 5439 nsize = GST_READ_UINT16_BE (map.data); 5440 nsize = MIN (nsize, map.size - 2); 5441 5442 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "", 5443 nsize, map.size); 5444 5445 /* takes care of UTF-8 validation or UTF-16 recognition, 5446 * no other encoding expected */ 5447 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL); 5448 gst_buffer_unmap (buf, &map); 5449 if (str) { 5450 gst_buffer_unref (buf); 5451 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free); 5452 } else { 5453 /* this should not really happen unless the subtitle is corrupted */ 5454 gst_buffer_unref (buf); 5455 buf = NULL; 5456 } 5457 5458 /* FIXME ? convert optional subsequent style info to markup */ 5459 5460 return buf; 5461 } 5462 5463 /* Sets a buffer's attributes properly and pushes it downstream. 5464 * Also checks for additional actions and custom processing that may 5465 * need to be done first. 5466 */ 5467 static GstFlowReturn 5468 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux, 5469 QtDemuxStream * stream, GstBuffer * buf, 5470 GstClockTime dts, GstClockTime pts, GstClockTime duration, 5471 gboolean keyframe, GstClockTime position, guint64 byte_position) 5472 { 5473 GstFlowReturn ret = GST_FLOW_OK; 5474 5475 /* offset the timestamps according to the edit list */ 5476 5477 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) { 5478 gchar *url; 5479 GstMapInfo map; 5480 5481 gst_buffer_map (buf, &map, GST_MAP_READ); 5482 url = g_strndup ((gchar *) map.data, map.size); 5483 gst_buffer_unmap (buf, &map); 5484 if (url != NULL && strlen (url) != 0) { 5485 /* we have RTSP redirect now */ 5486 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), 5487 gst_message_new_element (GST_OBJECT_CAST (qtdemux), 5488 gst_structure_new ("redirect", 5489 "new-location", G_TYPE_STRING, url, NULL))); 5490 qtdemux->posted_redirect = TRUE; 5491 } else { 5492 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not " 5493 "posting"); 5494 } 5495 g_free (url); 5496 } 5497 5498 /* position reporting */ 5499 if (qtdemux->segment.rate >= 0) { 5500 qtdemux->segment.position = position; 5501 gst_qtdemux_sync_streams (qtdemux); 5502 } 5503 5504 if (G_UNLIKELY (!stream->pad)) { 5505 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring"); 5506 gst_buffer_unref (buf); 5507 goto exit; 5508 } 5509 5510 /* send out pending buffers */ 5511 while (stream->buffers) { 5512 GstBuffer *buffer = (GstBuffer *) stream->buffers->data; 5513 5514 if (G_UNLIKELY (stream->discont)) { 5515 GST_LOG_OBJECT (qtdemux, "marking discont buffer"); 5516 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); 5517 stream->discont = FALSE; 5518 } else { 5519 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT); 5520 } 5521 5522 if (stream->alignment > 1) 5523 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment); 5524 gst_pad_push (stream->pad, buffer); 5525 5526 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers); 5527 } 5528 5529 /* we're going to modify the metadata */ 5530 buf = gst_buffer_make_writable (buf); 5531 5532 if (G_UNLIKELY (stream->need_process)) 5533 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf); 5534 5535 if (!buf) { 5536 goto exit; 5537 } 5538 5539 GST_BUFFER_DTS (buf) = dts; 5540 GST_BUFFER_PTS (buf) = pts; 5541 GST_BUFFER_DURATION (buf) = duration; 5542 GST_BUFFER_OFFSET (buf) = -1; 5543 GST_BUFFER_OFFSET_END (buf) = -1; 5544 5545 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette)) 5546 gst_buffer_append_memory (buf, 5547 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette)); 5548 5549 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) { 5550 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1); 5551 } 5552 #if 0 5553 if (G_UNLIKELY (qtdemux->element_index)) { 5554 GstClockTime stream_time; 5555 5556 stream_time = 5557 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME, 5558 timestamp); 5559 if (GST_CLOCK_TIME_IS_VALID (stream_time)) { 5560 GST_LOG_OBJECT (qtdemux, 5561 "adding association %" GST_TIME_FORMAT "-> %" 5562 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position); 5563 gst_index_add_association (qtdemux->element_index, 5564 qtdemux->index_id, 5565 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT : 5566 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time, 5567 GST_FORMAT_BYTES, byte_position, NULL); 5568 } 5569 } 5570 #endif 5571 5572 if (stream->need_clip) 5573 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf); 5574 5575 if (G_UNLIKELY (buf == NULL)) 5576 goto exit; 5577 5578 if (G_UNLIKELY (stream->discont)) { 5579 GST_LOG_OBJECT (qtdemux, "marking discont buffer"); 5580 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); 5581 stream->discont = FALSE; 5582 } else { 5583 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT); 5584 } 5585 5586 if (!keyframe) { 5587 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); 5588 stream->on_keyframe = FALSE; 5589 } else { 5590 stream->on_keyframe = TRUE; 5591 } 5592 5593 5594 GST_LOG_OBJECT (qtdemux, 5595 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT 5596 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts), 5597 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration), 5598 GST_PAD_NAME (stream->pad)); 5599 5600 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) { 5601 GstStructure *crypto_info; 5602 QtDemuxCencSampleSetInfo *info = 5603 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info; 5604 gint index; 5605 GstEvent *event; 5606 5607 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) { 5608 gst_pad_push_event (stream->pad, event); 5609 } 5610 5611 if (info->crypto_info == NULL) { 5612 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet"); 5613 gst_buffer_unref (buf); 5614 goto exit; 5615 } 5616 5617 /* The end of the crypto_info array matches our n_samples position, 5618 * so count backward from there */ 5619 index = stream->sample_index - stream->n_samples + info->crypto_info->len; 5620 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) { 5621 /* steal structure from array */ 5622 crypto_info = g_ptr_array_index (info->crypto_info, index); 5623 g_ptr_array_index (info->crypto_info, index) = NULL; 5624 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index, 5625 info->crypto_info->len); 5626 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) 5627 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer"); 5628 } else { 5629 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d", 5630 index, stream->sample_index); 5631 } 5632 } 5633 5634 if (stream->alignment > 1) 5635 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment); 5636 5637 ret = gst_pad_push (stream->pad, buf); 5638 5639 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) { 5640 /* mark position in stream, we'll need this to know when to send GAP event */ 5641 stream->segment.position = pts + duration; 5642 } 5643 5644 exit: 5645 return ret; 5646 } 5647 5648 static const QtDemuxRandomAccessEntry * 5649 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream, 5650 GstClockTime pos, gboolean after) 5651 { 5652 QtDemuxRandomAccessEntry *entries = stream->ra_entries; 5653 guint n_entries = stream->n_ra_entries; 5654 guint i; 5655 5656 /* we assume the table is sorted */ 5657 for (i = 0; i < n_entries; ++i) { 5658 if (entries[i].ts > pos) 5659 break; 5660 } 5661 5662 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's 5663 * probably okay to assume that the index lists the very first fragment */ 5664 if (i == 0) 5665 return &entries[0]; 5666 5667 if (after) 5668 return &entries[i]; 5669 else 5670 return &entries[i - 1]; 5671 } 5672 5673 static gboolean 5674 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux) 5675 { 5676 const QtDemuxRandomAccessEntry *best_entry = NULL; 5677 guint i; 5678 5679 GST_OBJECT_LOCK (qtdemux); 5680 5681 g_assert (qtdemux->n_streams > 0); 5682 5683 /* first see if we can determine where to go to using mfra, 5684 * before we start clearing things */ 5685 for (i = 0; i < qtdemux->n_streams; i++) { 5686 const QtDemuxRandomAccessEntry *entry; 5687 QtDemuxStream *stream; 5688 gboolean is_audio_or_video; 5689 5690 stream = qtdemux->streams[i]; 5691 5692 if (stream->ra_entries == NULL) 5693 continue; 5694 5695 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun) 5696 is_audio_or_video = TRUE; 5697 else 5698 is_audio_or_video = FALSE; 5699 5700 entry = 5701 gst_qtdemux_stream_seek_fragment (qtdemux, stream, 5702 stream->time_position, !is_audio_or_video); 5703 5704 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset " 5705 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset); 5706 5707 stream->pending_seek = entry; 5708 5709 /* decide position to jump to just based on audio/video tracks, not subs */ 5710 if (!is_audio_or_video) 5711 continue; 5712 5713 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset) 5714 best_entry = entry; 5715 } 5716 5717 /* no luck, will handle seek otherwise */ 5718 if (best_entry == NULL) { 5719 GST_OBJECT_UNLOCK (qtdemux); 5720 return FALSE; 5721 } 5722 5723 /* ok, now we can prepare for processing as of located moof */ 5724 for (i = 0; i < qtdemux->n_streams; i++) { 5725 QtDemuxStream *stream; 5726 5727 stream = qtdemux->streams[i]; 5728 5729 g_free (stream->samples); 5730 stream->samples = NULL; 5731 stream->n_samples = 0; 5732 stream->stbl_index = -1; /* no samples have yet been parsed */ 5733 stream->sample_index = -1; 5734 5735 if (stream->protection_scheme_info) { 5736 /* Clear out any old cenc crypto info entries as we'll move to a new moof */ 5737 if (stream->protection_scheme_type == FOURCC_cenc) { 5738 QtDemuxCencSampleSetInfo *info = 5739 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info; 5740 if (info->crypto_info) { 5741 g_ptr_array_free (info->crypto_info, TRUE); 5742 info->crypto_info = NULL; 5743 } 5744 } 5745 } 5746 } 5747 5748 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment " 5749 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT, 5750 GST_TIME_ARGS (qtdemux->streams[0]->time_position), 5751 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts)); 5752 5753 qtdemux->moof_offset = best_entry->moof_offset; 5754 5755 qtdemux_add_fragmented_samples (qtdemux); 5756 5757 GST_OBJECT_UNLOCK (qtdemux); 5758 return TRUE; 5759 } 5760 5761 static GstFlowReturn 5762 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux) 5763 { 5764 GstFlowReturn ret = GST_FLOW_OK; 5765 GstBuffer *buf = NULL; 5766 QtDemuxStream *stream; 5767 GstClockTime min_time; 5768 guint64 offset = 0; 5769 GstClockTime dts = GST_CLOCK_TIME_NONE; 5770 GstClockTime pts = GST_CLOCK_TIME_NONE; 5771 GstClockTime duration = 0; 5772 gboolean keyframe = FALSE; 5773 guint sample_size = 0; 5774 gboolean empty = 0; 5775 guint size; 5776 gint index; 5777 gint i; 5778 5779 gst_qtdemux_push_pending_newsegment (qtdemux); 5780 5781 if (qtdemux->fragmented_seek_pending) { 5782 GST_INFO_OBJECT (qtdemux, "pending fragmented seek"); 5783 if (gst_qtdemux_do_fragmented_seek (qtdemux)) { 5784 GST_INFO_OBJECT (qtdemux, "fragmented seek done!"); 5785 qtdemux->fragmented_seek_pending = FALSE; 5786 } else { 5787 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending"); 5788 } 5789 } 5790 5791 /* Figure out the next stream sample to output, min_time is expressed in 5792 * global time and runs over the edit list segments. */ 5793 min_time = G_MAXUINT64; 5794 index = -1; 5795 for (i = 0; i < qtdemux->n_streams; i++) { 5796 GstClockTime position; 5797 5798 stream = qtdemux->streams[i]; 5799 position = stream->time_position; 5800 5801 /* position of -1 is EOS */ 5802 if (position != GST_CLOCK_TIME_NONE && position < min_time) { 5803 min_time = position; 5804 index = i; 5805 } 5806 } 5807 /* all are EOS */ 5808 if (G_UNLIKELY (index == -1)) { 5809 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS"); 5810 goto eos; 5811 } 5812 5813 /* check for segment end */ 5814 if (G_UNLIKELY (qtdemux->segment.stop != -1 5815 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time) 5816 || (qtdemux->segment.rate < 0 5817 && qtdemux->segment.start > min_time)) 5818 && qtdemux->streams[index]->on_keyframe)) { 5819 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment."); 5820 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE; 5821 goto eos_stream; 5822 } 5823 5824 /* gap events for subtitle streams */ 5825 for (i = 0; i < qtdemux->n_streams; i++) { 5826 stream = qtdemux->streams[i]; 5827 if (stream->pad && (stream->subtype == FOURCC_subp 5828 || stream->subtype == FOURCC_text 5829 || stream->subtype == FOURCC_sbtl)) { 5830 /* send one second gap events until the stream catches up */ 5831 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */ 5832 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) && 5833 GST_CLOCK_TIME_IS_VALID (stream->segment.position) && 5834 stream->segment.position + GST_SECOND < min_time) { 5835 GstEvent *gap = 5836 gst_event_new_gap (stream->segment.position, GST_SECOND); 5837 gst_pad_push_event (stream->pad, gap); 5838 stream->segment.position += GST_SECOND; 5839 } 5840 } 5841 } 5842 5843 stream = qtdemux->streams[index]; 5844 /* fetch info for the current sample of this stream */ 5845 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty, 5846 &offset, &sample_size, &dts, &pts, &duration, &keyframe))) 5847 goto eos_stream; 5848 5849 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream); 5850 if (stream->new_caps) { 5851 gst_qtdemux_configure_stream (qtdemux, stream); 5852 qtdemux_do_allocation (qtdemux, stream); 5853 } 5854 5855 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */ 5856 if (G_UNLIKELY (qtdemux-> 5857 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) { 5858 if (stream->subtype == FOURCC_vide && !keyframe) { 5859 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index); 5860 goto next; 5861 } 5862 } 5863 5864 GST_DEBUG_OBJECT (qtdemux, 5865 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT 5866 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT 5867 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size, 5868 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration)); 5869 5870 if (G_UNLIKELY (empty)) { 5871 /* empty segment, push a gap if there's a second or more 5872 * difference and move to the next one */ 5873 if ((pts + duration - stream->segment.position) >= GST_SECOND) 5874 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration)); 5875 stream->segment.position = pts + duration; 5876 goto next; 5877 } 5878 5879 /* hmm, empty sample, skip and move to next sample */ 5880 if (G_UNLIKELY (sample_size <= 0)) 5881 goto next; 5882 5883 /* last pushed sample was out of boundary, goto next sample */ 5884 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS)) 5885 goto next; 5886 5887 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) { 5888 size = sample_size; 5889 } else { 5890 GST_DEBUG_OBJECT (qtdemux, 5891 "size %d larger than stream max_buffer_size %d, trimming", 5892 sample_size, stream->max_buffer_size); 5893 size = 5894 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size); 5895 } 5896 5897 if (qtdemux->cenc_aux_info_offset > 0) { 5898 GstMapInfo map; 5899 GstByteReader br; 5900 GstBuffer *aux_info = NULL; 5901 5902 /* pull the data stored before the sample */ 5903 ret = 5904 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset, 5905 offset + stream->offset_in_sample - qtdemux->offset, &aux_info); 5906 if (G_UNLIKELY (ret != GST_FLOW_OK)) 5907 goto beach; 5908 gst_buffer_map (aux_info, &map, GST_MAP_READ); 5909 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info"); 5910 gst_byte_reader_init (&br, map.data + 8, map.size); 5911 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br, 5912 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) { 5913 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info"); 5914 gst_buffer_unmap (aux_info, &map); 5915 gst_buffer_unref (aux_info); 5916 ret = GST_FLOW_ERROR; 5917 goto beach; 5918 } 5919 gst_buffer_unmap (aux_info, &map); 5920 gst_buffer_unref (aux_info); 5921 } 5922 5923 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size, 5924 offset); 5925 5926 if (stream->use_allocator) { 5927 /* if we have a per-stream allocator, use it */ 5928 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params); 5929 } 5930 5931 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample, 5932 size, &buf); 5933 if (G_UNLIKELY (ret != GST_FLOW_OK)) 5934 goto beach; 5935 5936 if (size != sample_size) { 5937 pts += gst_util_uint64_scale_int (GST_SECOND, 5938 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame, 5939 stream->timescale); 5940 dts += 5941 gst_util_uint64_scale_int (GST_SECOND, 5942 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame, 5943 stream->timescale); 5944 duration = 5945 gst_util_uint64_scale_int (GST_SECOND, 5946 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale); 5947 } 5948 5949 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf, 5950 dts, pts, duration, keyframe, min_time, offset); 5951 5952 if (size != sample_size) { 5953 QtDemuxSample *sample = &stream->samples[stream->sample_index]; 5954 QtDemuxSegment *segment = &stream->segments[stream->segment_index]; 5955 5956 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream, 5957 sample->timestamp + 5958 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame); 5959 if (time_position >= segment->media_start) { 5960 /* inside the segment, update time_position, looks very familiar to 5961 * GStreamer segments, doesn't it? */ 5962 stream->time_position = (time_position - segment->media_start) + 5963 segment->time; 5964 } else { 5965 /* not yet in segment, time does not yet increment. This means 5966 * that we are still prerolling keyframes to the decoder so it can 5967 * decode the first sample of the segment. */ 5968 stream->time_position = segment->time; 5969 } 5970 } 5971 5972 /* combine flows */ 5973 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret); 5974 /* ignore unlinked, we will not push on the pad anymore and we will EOS when 5975 * we have no more data for the pad to push */ 5976 if (ret == GST_FLOW_EOS) 5977 ret = GST_FLOW_OK; 5978 5979 stream->offset_in_sample += size; 5980 if (stream->offset_in_sample >= sample_size) { 5981 gst_qtdemux_advance_sample (qtdemux, stream); 5982 } 5983 goto beach; 5984 5985 next: 5986 gst_qtdemux_advance_sample (qtdemux, stream); 5987 5988 beach: 5989 return ret; 5990 5991 /* special cases */ 5992 eos: 5993 { 5994 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS"); 5995 ret = GST_FLOW_EOS; 5996 goto beach; 5997 } 5998 eos_stream: 5999 { 6000 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream"); 6001 /* EOS will be raised if all are EOS */ 6002 ret = GST_FLOW_OK; 6003 goto beach; 6004 } 6005 } 6006 6007 static void 6008 gst_qtdemux_loop (GstPad * pad) 6009 { 6010 GstQTDemux *qtdemux; 6011 guint64 cur_offset; 6012 GstFlowReturn ret; 6013 6014 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad)); 6015 6016 cur_offset = qtdemux->offset; 6017 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s", 6018 cur_offset, qt_demux_state_string (qtdemux->state)); 6019 6020 switch (qtdemux->state) { 6021 case QTDEMUX_STATE_INITIAL: 6022 case QTDEMUX_STATE_HEADER: 6023 ret = gst_qtdemux_loop_state_header (qtdemux); 6024 break; 6025 case QTDEMUX_STATE_MOVIE: 6026 ret = gst_qtdemux_loop_state_movie (qtdemux); 6027 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) { 6028 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux); 6029 } 6030 break; 6031 default: 6032 /* ouch */ 6033 goto invalid_state; 6034 } 6035 6036 /* if something went wrong, pause */ 6037 if (ret != GST_FLOW_OK) 6038 goto pause; 6039 6040 done: 6041 gst_object_unref (qtdemux); 6042 return; 6043 6044 /* ERRORS */ 6045 invalid_state: 6046 { 6047 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED, 6048 (NULL), ("streaming stopped, invalid state")); 6049 gst_pad_pause_task (pad); 6050 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ()); 6051 goto done; 6052 } 6053 pause: 6054 { 6055 const gchar *reason = gst_flow_get_name (ret); 6056 6057 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason); 6058 6059 gst_pad_pause_task (pad); 6060 6061 /* fatal errors need special actions */ 6062 /* check EOS */ 6063 if (ret == GST_FLOW_EOS) { 6064 if (qtdemux->n_streams == 0) { 6065 /* we have no streams, post an error */ 6066 gst_qtdemux_post_no_playable_stream_error (qtdemux); 6067 } 6068 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) { 6069 gint64 stop; 6070 6071 if ((stop = qtdemux->segment.stop) == -1) 6072 stop = qtdemux->segment.duration; 6073 6074 if (qtdemux->segment.rate >= 0) { 6075 GstMessage *message; 6076 GstEvent *event; 6077 6078 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment"); 6079 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux), 6080 GST_FORMAT_TIME, stop); 6081 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop); 6082 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) { 6083 gst_message_set_seqnum (message, qtdemux->segment_seqnum); 6084 gst_event_set_seqnum (event, qtdemux->segment_seqnum); 6085 } 6086 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message); 6087 gst_qtdemux_push_event (qtdemux, event); 6088 } else { 6089 GstMessage *message; 6090 GstEvent *event; 6091 6092 /* For Reverse Playback */ 6093 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment"); 6094 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux), 6095 GST_FORMAT_TIME, qtdemux->segment.start); 6096 event = gst_event_new_segment_done (GST_FORMAT_TIME, 6097 qtdemux->segment.start); 6098 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) { 6099 gst_message_set_seqnum (message, qtdemux->segment_seqnum); 6100 gst_event_set_seqnum (event, qtdemux->segment_seqnum); 6101 } 6102 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message); 6103 gst_qtdemux_push_event (qtdemux, event); 6104 } 6105 } else { 6106 GstEvent *event; 6107 6108 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment"); 6109 event = gst_event_new_eos (); 6110 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) 6111 gst_event_set_seqnum (event, qtdemux->segment_seqnum); 6112 gst_qtdemux_push_event (qtdemux, event); 6113 } 6114 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) { 6115 GST_ELEMENT_FLOW_ERROR (qtdemux, ret); 6116 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ()); 6117 } 6118 goto done; 6119 } 6120 } 6121 6122 /* 6123 * has_next_entry 6124 * 6125 * Returns if there are samples to be played. 6126 */ 6127 static gboolean 6128 has_next_entry (GstQTDemux * demux) 6129 { 6130 QtDemuxStream *stream; 6131 int i; 6132 6133 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet"); 6134 6135 for (i = 0; i < demux->n_streams; i++) { 6136 stream = demux->streams[i]; 6137 6138 if (stream->sample_index == -1) { 6139 stream->sample_index = 0; 6140 stream->offset_in_sample = 0; 6141 } 6142 6143 if (stream->sample_index >= stream->n_samples) { 6144 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i); 6145 continue; 6146 } 6147 GST_DEBUG_OBJECT (demux, "Found a sample"); 6148 return TRUE; 6149 } 6150 6151 GST_DEBUG_OBJECT (demux, "There wasn't any next sample"); 6152 return FALSE; 6153 } 6154 6155 /* 6156 * next_entry_size 6157 * 6158 * Returns the size of the first entry at the current offset. 6159 * If -1, there are none (which means EOS or empty file). 6160 */ 6161 static guint64 6162 next_entry_size (GstQTDemux * demux) 6163 { 6164 QtDemuxStream *stream; 6165 int i; 6166 int smallidx = -1; 6167 guint64 smalloffs = (guint64) - 1; 6168 QtDemuxSample *sample; 6169 6170 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT, 6171 demux->offset); 6172 6173 for (i = 0; i < demux->n_streams; i++) { 6174 stream = demux->streams[i]; 6175 6176 if (stream->sample_index == -1) { 6177 stream->sample_index = 0; 6178 stream->offset_in_sample = 0; 6179 } 6180 6181 if (stream->sample_index >= stream->n_samples) { 6182 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i); 6183 continue; 6184 } 6185 6186 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) { 6187 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!", 6188 stream->sample_index); 6189 return -1; 6190 } 6191 6192 sample = &stream->samples[stream->sample_index]; 6193 6194 GST_LOG_OBJECT (demux, 6195 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT 6196 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index, 6197 sample->offset, sample->size); 6198 6199 if (((smalloffs == -1) 6200 || (sample->offset < smalloffs)) && (sample->size)) { 6201 smallidx = i; 6202 smalloffs = sample->offset; 6203 } 6204 } 6205 6206 GST_LOG_OBJECT (demux, 6207 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%" 6208 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset); 6209 6210 if (smallidx == -1) 6211 return -1; 6212 6213 stream = demux->streams[smallidx]; 6214 sample = &stream->samples[stream->sample_index]; 6215 6216 if (sample->offset >= demux->offset) { 6217 demux->todrop = sample->offset - demux->offset; 6218 return sample->size + demux->todrop; 6219 } 6220 6221 GST_DEBUG_OBJECT (demux, 6222 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset); 6223 return -1; 6224 } 6225 6226 static void 6227 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom) 6228 { 6229 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom); 6230 6231 gst_element_post_message (GST_ELEMENT_CAST (demux), 6232 gst_message_new_element (GST_OBJECT_CAST (demux), 6233 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL))); 6234 } 6235 6236 static gboolean 6237 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset) 6238 { 6239 GstEvent *event; 6240 gboolean res = 0; 6241 6242 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset); 6243 6244 event = 6245 gst_event_new_seek (1.0, GST_FORMAT_BYTES, 6246 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset, 6247 GST_SEEK_TYPE_NONE, -1); 6248 6249 /* store seqnum to drop flush events, they don't need to reach downstream */ 6250 demux->offset_seek_seqnum = gst_event_get_seqnum (event); 6251 res = gst_pad_push_event (demux->sinkpad, event); 6252 demux->offset_seek_seqnum = GST_SEQNUM_INVALID; 6253 6254 return res; 6255 } 6256 6257 /* check for seekable upstream, above and beyond a mere query */ 6258 static void 6259 gst_qtdemux_check_seekability (GstQTDemux * demux) 6260 { 6261 GstQuery *query; 6262 gboolean seekable = FALSE; 6263 gint64 start = -1, stop = -1; 6264 6265 if (demux->upstream_size) 6266 return; 6267 6268 if (demux->upstream_format_is_time) 6269 return; 6270 6271 query = gst_query_new_seeking (GST_FORMAT_BYTES); 6272 if (!gst_pad_peer_query (demux->sinkpad, query)) { 6273 GST_DEBUG_OBJECT (demux, "seeking query failed"); 6274 goto done; 6275 } 6276 6277 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop); 6278 6279 /* try harder to query upstream size if we didn't get it the first time */ 6280 if (seekable && stop == -1) { 6281 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop"); 6282 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop); 6283 } 6284 6285 /* if upstream doesn't know the size, it's likely that it's not seekable in 6286 * practice even if it technically may be seekable */ 6287 if (seekable && (start != 0 || stop <= start)) { 6288 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable"); 6289 seekable = FALSE; 6290 } 6291 6292 done: 6293 gst_query_unref (query); 6294 6295 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %" 6296 G_GUINT64_FORMAT ")", seekable, start, stop); 6297 demux->upstream_seekable = seekable; 6298 demux->upstream_size = seekable ? stop : -1; 6299 } 6300 6301 static void 6302 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes) 6303 { 6304 g_return_if_fail (bytes <= demux->todrop); 6305 6306 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes); 6307 gst_adapter_flush (demux->adapter, bytes); 6308 demux->neededbytes -= bytes; 6309 demux->offset += bytes; 6310 demux->todrop -= bytes; 6311 } 6312 6313 static void 6314 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux) 6315 { 6316 if (G_UNLIKELY (demux->pending_newsegment)) { 6317 gint i; 6318 6319 gst_qtdemux_push_pending_newsegment (demux); 6320 /* clear to send tags on all streams */ 6321 for (i = 0; i < demux->n_streams; i++) { 6322 QtDemuxStream *stream; 6323 stream = demux->streams[i]; 6324 gst_qtdemux_push_tags (demux, stream); 6325 if (CUR_STREAM (stream)->sparse) { 6326 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i); 6327 gst_pad_push_event (stream->pad, 6328 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE)); 6329 } 6330 } 6331 } 6332 } 6333 6334 static void 6335 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux, 6336 QtDemuxStream * stream, gint segment_index, GstClockTime pos) 6337 { 6338 GstClockTime ts, dur; 6339 GstEvent *gap; 6340 6341 ts = pos; 6342 dur = 6343 stream->segments[segment_index].duration - (pos - 6344 stream->segments[segment_index].time); 6345 gap = gst_event_new_gap (ts, dur); 6346 stream->time_position += dur; 6347 6348 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty " 6349 "segment: %" GST_PTR_FORMAT, gap); 6350 gst_pad_push_event (stream->pad, gap); 6351 } 6352 6353 static void 6354 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux, 6355 QtDemuxStream * stream) 6356 { 6357 gint i; 6358 6359 /* Push any initial gap segments before proceeding to the 6360 * 'real' data */ 6361 for (i = 0; i < stream->n_segments; i++) { 6362 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position); 6363 6364 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) { 6365 gst_qtdemux_send_gap_for_segment (demux, stream, i, 6366 stream->time_position); 6367 } else { 6368 /* Only support empty segment at the beginning followed by 6369 * one non-empty segment, this was checked when parsing the 6370 * edts atom, arriving here is unexpected */ 6371 g_assert (i + 1 == stream->n_segments); 6372 break; 6373 } 6374 } 6375 } 6376 6377 static GstFlowReturn 6378 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf) 6379 { 6380 GstQTDemux *demux; 6381 6382 demux = GST_QTDEMUX (parent); 6383 6384 GST_DEBUG_OBJECT (demux, 6385 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT 6386 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%" 6387 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)), 6388 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf), 6389 gst_buffer_get_size (inbuf), demux->offset); 6390 6391 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) { 6392 gboolean is_gap_input = FALSE; 6393 gint i; 6394 6395 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT"); 6396 6397 for (i = 0; i < demux->n_streams; i++) { 6398 demux->streams[i]->discont = TRUE; 6399 } 6400 6401 /* Check if we can land back on our feet in the case where upstream is 6402 * handling the seeking/pushing of samples with gaps in between (like 6403 * in the case of trick-mode DASH for example) */ 6404 if (demux->upstream_format_is_time 6405 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) { 6406 gint i; 6407 for (i = 0; i < demux->n_streams; i++) { 6408 guint32 res; 6409 GST_LOG_OBJECT (demux, 6410 "Stream #%d , checking if offset %" G_GUINT64_FORMAT 6411 " is a sample start", i, GST_BUFFER_OFFSET (inbuf)); 6412 res = 6413 gst_qtdemux_find_index_for_given_media_offset_linear (demux, 6414 demux->streams[i], GST_BUFFER_OFFSET (inbuf)); 6415 if (res != -1) { 6416 QtDemuxSample *sample = &demux->streams[i]->samples[res]; 6417 GST_LOG_OBJECT (demux, 6418 "Checking if sample %d from stream %d is valid (offset:%" 6419 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i, 6420 sample->offset, sample->size); 6421 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) { 6422 GST_LOG_OBJECT (demux, 6423 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT, 6424 res); 6425 is_gap_input = TRUE; 6426 /* We can go back to standard playback mode */ 6427 demux->state = QTDEMUX_STATE_MOVIE; 6428 /* Remember which sample this stream is at */ 6429 demux->streams[i]->sample_index = res; 6430 /* Finally update all push-based values to the expected values */ 6431 demux->neededbytes = demux->streams[i]->samples[res].size; 6432 demux->offset = GST_BUFFER_OFFSET (inbuf); 6433 demux->mdatleft = 6434 demux->mdatsize - demux->offset + demux->mdatoffset; 6435 demux->todrop = 0; 6436 } 6437 } 6438 } 6439 if (!is_gap_input) { 6440 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT"); 6441 /* Reset state if it's a real discont */ 6442 demux->neededbytes = 16; 6443 demux->state = QTDEMUX_STATE_INITIAL; 6444 demux->offset = GST_BUFFER_OFFSET (inbuf); 6445 gst_adapter_clear (demux->adapter); 6446 } 6447 } 6448 /* Reverse fragmented playback, need to flush all we have before 6449 * consuming a new fragment. 6450 * The samples array have the timestamps calculated by accumulating the 6451 * durations but this won't work for reverse playback of fragments as 6452 * the timestamps of a subsequent fragment should be smaller than the 6453 * previously received one. */ 6454 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) { 6455 gst_qtdemux_process_adapter (demux, TRUE); 6456 for (i = 0; i < demux->n_streams; i++) 6457 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]); 6458 } 6459 } 6460 6461 gst_adapter_push (demux->adapter, inbuf); 6462 6463 GST_DEBUG_OBJECT (demux, 6464 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf, 6465 demux->neededbytes, gst_adapter_available (demux->adapter)); 6466 6467 return gst_qtdemux_process_adapter (demux, FALSE); 6468 } 6469 6470 static GstFlowReturn 6471 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force) 6472 { 6473 GstFlowReturn ret = GST_FLOW_OK; 6474 6475 /* we never really mean to buffer that much */ 6476 if (demux->neededbytes == -1) { 6477 goto eos; 6478 } 6479 6480 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) && 6481 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) { 6482 6483 #ifndef GST_DISABLE_GST_DEBUG 6484 { 6485 guint64 discont_offset, distance_from_discont; 6486 6487 discont_offset = gst_adapter_offset_at_discont (demux->adapter); 6488 distance_from_discont = 6489 gst_adapter_distance_from_discont (demux->adapter); 6490 6491 GST_DEBUG_OBJECT (demux, 6492 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT 6493 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT 6494 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes, 6495 demux->offset, discont_offset, distance_from_discont); 6496 } 6497 #endif 6498 6499 switch (demux->state) { 6500 case QTDEMUX_STATE_INITIAL:{ 6501 const guint8 *data; 6502 guint32 fourcc; 6503 guint64 size; 6504 6505 gst_qtdemux_check_seekability (demux); 6506 6507 data = gst_adapter_map (demux->adapter, demux->neededbytes); 6508 6509 /* get fourcc/length, set neededbytes */ 6510 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes, 6511 &size, &fourcc); 6512 gst_adapter_unmap (demux->adapter); 6513 data = NULL; 6514 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] " 6515 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size); 6516 if (size == 0) { 6517 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, 6518 (_("This file is invalid and cannot be played.")), 6519 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length", 6520 GST_FOURCC_ARGS (fourcc))); 6521 ret = GST_FLOW_ERROR; 6522 break; 6523 } 6524 if (fourcc == FOURCC_mdat) { 6525 gint next_entry = next_entry_size (demux); 6526 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) { 6527 /* we have the headers, start playback */ 6528 demux->state = QTDEMUX_STATE_MOVIE; 6529 demux->neededbytes = next_entry; 6530 demux->mdatleft = size; 6531 demux->mdatsize = demux->mdatleft; 6532 } else { 6533 /* no headers yet, try to get them */ 6534 guint bs; 6535 gboolean res; 6536 guint64 old, target; 6537 6538 buffer_data: 6539 old = demux->offset; 6540 target = old + size; 6541 6542 /* try to jump over the atom with a seek */ 6543 /* only bother if it seems worth doing so, 6544 * and avoids possible upstream/server problems */ 6545 if (demux->upstream_seekable && 6546 demux->upstream_size > 4 * (1 << 20)) { 6547 res = qtdemux_seek_offset (demux, target); 6548 } else { 6549 GST_DEBUG_OBJECT (demux, "skipping seek"); 6550 res = FALSE; 6551 } 6552 6553 if (res) { 6554 GST_DEBUG_OBJECT (demux, "seek success"); 6555 /* remember the offset fo the first mdat so we can seek back to it 6556 * after we have the headers */ 6557 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) { 6558 demux->first_mdat = old; 6559 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT, 6560 demux->first_mdat); 6561 } 6562 /* seek worked, continue reading */ 6563 demux->offset = target; 6564 demux->neededbytes = 16; 6565 demux->state = QTDEMUX_STATE_INITIAL; 6566 } else { 6567 /* seek failed, need to buffer */ 6568 demux->offset = old; 6569 GST_DEBUG_OBJECT (demux, "seek failed/skipped"); 6570 /* there may be multiple mdat (or alike) buffers */ 6571 /* sanity check */ 6572 if (demux->mdatbuffer) 6573 bs = gst_buffer_get_size (demux->mdatbuffer); 6574 else 6575 bs = 0; 6576 if (size + bs > 10 * (1 << 20)) 6577 goto no_moov; 6578 demux->state = QTDEMUX_STATE_BUFFER_MDAT; 6579 demux->neededbytes = size; 6580 if (!demux->mdatbuffer) 6581 demux->mdatoffset = demux->offset; 6582 } 6583 } 6584 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) { 6585 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, 6586 (_("This file is invalid and cannot be played.")), 6587 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT, 6588 GST_FOURCC_ARGS (fourcc), size)); 6589 ret = GST_FLOW_ERROR; 6590 break; 6591 } else { 6592 /* this means we already started buffering and still no moov header, 6593 * let's continue buffering everything till we get moov */ 6594 if (demux->mdatbuffer && !(fourcc == FOURCC_moov 6595 || fourcc == FOURCC_moof)) 6596 goto buffer_data; 6597 demux->neededbytes = size; 6598 demux->state = QTDEMUX_STATE_HEADER; 6599 } 6600 break; 6601 } 6602 case QTDEMUX_STATE_HEADER:{ 6603 const guint8 *data; 6604 guint32 fourcc; 6605 6606 GST_DEBUG_OBJECT (demux, "In header"); 6607 6608 data = gst_adapter_map (demux->adapter, demux->neededbytes); 6609 6610 /* parse the header */ 6611 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL, 6612 &fourcc); 6613 if (fourcc == FOURCC_moov) { 6614 gint n; 6615 6616 /* in usual fragmented setup we could try to scan for more 6617 * and end up at the the moov (after mdat) again */ 6618 if (demux->got_moov && demux->n_streams > 0 && 6619 (!demux->fragmented 6620 || demux->last_moov_offset == demux->offset)) { 6621 GST_DEBUG_OBJECT (demux, 6622 "Skipping moov atom as we have (this) one already"); 6623 } else { 6624 GST_DEBUG_OBJECT (demux, "Parsing [moov]"); 6625 6626 if (demux->got_moov && demux->fragmented) { 6627 GST_DEBUG_OBJECT (demux, 6628 "Got a second moov, clean up data from old one"); 6629 if (demux->moov_node_compressed) { 6630 g_node_destroy (demux->moov_node_compressed); 6631 if (demux->moov_node) 6632 g_free (demux->moov_node->data); 6633 } 6634 demux->moov_node_compressed = NULL; 6635 if (demux->moov_node) 6636 g_node_destroy (demux->moov_node); 6637 demux->moov_node = NULL; 6638 } else { 6639 /* prepare newsegment to send when streaming actually starts */ 6640 if (!demux->pending_newsegment) { 6641 demux->pending_newsegment = 6642 gst_event_new_segment (&demux->segment); 6643 if (demux->segment_seqnum != GST_SEQNUM_INVALID) 6644 gst_event_set_seqnum (demux->pending_newsegment, 6645 demux->segment_seqnum); 6646 } 6647 } 6648 6649 demux->last_moov_offset = demux->offset; 6650 6651 qtdemux_parse_moov (demux, data, demux->neededbytes); 6652 qtdemux_node_dump (demux, demux->moov_node); 6653 #ifdef GSTREAMER_LITE 6654 if (!qtdemux_parse_tree (demux)) 6655 { 6656 g_node_destroy (demux->moov_node); 6657 demux->moov_node = NULL; 6658 ret = GST_FLOW_ERROR; 6659 goto done; 6660 } 6661 #else 6662 qtdemux_parse_tree (demux); 6663 #endif //GSTREAMER_LITE 6664 qtdemux_prepare_streams (demux); 6665 if (!demux->got_moov) 6666 qtdemux_expose_streams (demux); 6667 else { 6668 6669 for (n = 0; n < demux->n_streams; n++) { 6670 QtDemuxStream *stream = demux->streams[n]; 6671 6672 gst_qtdemux_configure_stream (demux, stream); 6673 } 6674 } 6675 6676 demux->got_moov = TRUE; 6677 gst_qtdemux_check_send_pending_segment (demux); 6678 6679 /* fragmented streams headers shouldn't contain edts atoms */ 6680 if (!demux->fragmented) { 6681 for (n = 0; n < demux->n_streams; n++) { 6682 gst_qtdemux_stream_send_initial_gap_segments (demux, 6683 demux->streams[n]); 6684 } 6685 } 6686 6687 if (demux->moov_node_compressed) { 6688 g_node_destroy (demux->moov_node_compressed); 6689 g_free (demux->moov_node->data); 6690 } 6691 demux->moov_node_compressed = NULL; 6692 g_node_destroy (demux->moov_node); 6693 demux->moov_node = NULL; 6694 GST_DEBUG_OBJECT (demux, "Finished parsing the header"); 6695 } 6696 } else if (fourcc == FOURCC_moof) { 6697 if ((demux->got_moov || demux->media_caps) && demux->fragmented) { 6698 guint64 dist = 0; 6699 GstClockTime prev_pts; 6700 guint64 prev_offset; 6701 guint64 adapter_discont_offset, adapter_discont_dist; 6702 6703 GST_DEBUG_OBJECT (demux, "Parsing [moof]"); 6704 6705 /* 6706 * The timestamp of the moof buffer is relevant as some scenarios 6707 * won't have the initial timestamp in the atoms. Whenever a new 6708 * buffer has started, we get that buffer's PTS and use it as a base 6709 * timestamp for the trun entries. 6710 * 6711 * To keep track of the current buffer timestamp and starting point 6712 * we use gst_adapter_prev_pts that gives us the PTS and the distance 6713 * from the beggining of the buffer, with the distance and demux->offset 6714 * we know if it is still the same buffer or not. 6715 */ 6716 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist); 6717 prev_offset = demux->offset - dist; 6718 if (demux->fragment_start_offset == -1 6719 || prev_offset > demux->fragment_start_offset) { 6720 demux->fragment_start_offset = prev_offset; 6721 demux->fragment_start = prev_pts; 6722 GST_DEBUG_OBJECT (demux, 6723 "New fragment start found at: %" G_GUINT64_FORMAT " : %" 6724 GST_TIME_FORMAT, demux->fragment_start_offset, 6725 GST_TIME_ARGS (demux->fragment_start)); 6726 } 6727 6728 /* We can't use prev_offset() here because this would require 6729 * upstream to set consistent and correct offsets on all buffers 6730 * since the discont. Nothing ever did that in the past and we 6731 * would break backwards compatibility here then. 6732 * Instead take the offset we had at the last discont and count 6733 * the bytes from there. This works with old code as there would 6734 * be no discont between moov and moof, and also works with 6735 * adaptivedemux which correctly sets offset and will set the 6736 * DISCONT flag accordingly when needed. 6737 * 6738 * We also only do this for upstream TIME segments as otherwise 6739 * there are potential backwards compatibility problems with 6740 * seeking in PUSH mode and upstream providing inconsistent 6741 * timestamps. */ 6742 adapter_discont_offset = 6743 gst_adapter_offset_at_discont (demux->adapter); 6744 adapter_discont_dist = 6745 gst_adapter_distance_from_discont (demux->adapter); 6746 6747 GST_DEBUG_OBJECT (demux, 6748 "demux offset %" G_GUINT64_FORMAT " adapter offset %" 6749 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)", 6750 demux->offset, adapter_discont_offset, adapter_discont_dist); 6751 6752 if (demux->upstream_format_is_time) { 6753 demux->moof_offset = adapter_discont_offset; 6754 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE) 6755 demux->moof_offset += adapter_discont_dist; 6756 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE) 6757 demux->moof_offset = demux->offset; 6758 } else { 6759 demux->moof_offset = demux->offset; 6760 } 6761 6762 if (!qtdemux_parse_moof (demux, data, demux->neededbytes, 6763 demux->moof_offset, NULL)) { 6764 gst_adapter_unmap (demux->adapter); 6765 ret = GST_FLOW_ERROR; 6766 goto done; 6767 } 6768 /* in MSS we need to expose the pads after the first moof as we won't get a moov */ 6769 if (demux->mss_mode && !demux->exposed) { 6770 if (!demux->pending_newsegment) { 6771 GST_DEBUG_OBJECT (demux, "new pending_newsegment"); 6772 demux->pending_newsegment = 6773 gst_event_new_segment (&demux->segment); 6774 if (demux->segment_seqnum != GST_SEQNUM_INVALID) 6775 gst_event_set_seqnum (demux->pending_newsegment, 6776 demux->segment_seqnum); 6777 } 6778 qtdemux_expose_streams (demux); 6779 } 6780 } else { 6781 GST_DEBUG_OBJECT (demux, "Discarding [moof]"); 6782 } 6783 } else if (fourcc == FOURCC_ftyp) { 6784 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]"); 6785 qtdemux_parse_ftyp (demux, data, demux->neededbytes); 6786 } else if (fourcc == FOURCC_uuid) { 6787 GST_DEBUG_OBJECT (demux, "Parsing [uuid]"); 6788 qtdemux_parse_uuid (demux, data, demux->neededbytes); 6789 } else if (fourcc == FOURCC_sidx) { 6790 GST_DEBUG_OBJECT (demux, "Parsing [sidx]"); 6791 qtdemux_parse_sidx (demux, data, demux->neededbytes); 6792 } else { 6793 switch (fourcc) { 6794 case FOURCC_styp: 6795 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now 6796 * FALLTHROUGH */ 6797 case FOURCC_skip: 6798 case FOURCC_free: 6799 /* [free] and [skip] are padding atoms */ 6800 GST_DEBUG_OBJECT (demux, 6801 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT, 6802 GST_FOURCC_ARGS (fourcc)); 6803 break; 6804 default: 6805 GST_WARNING_OBJECT (demux, 6806 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT, 6807 GST_FOURCC_ARGS (fourcc)); 6808 /* Let's jump that one and go back to initial state */ 6809 break; 6810 } 6811 } 6812 gst_adapter_unmap (demux->adapter); 6813 data = NULL; 6814 6815 if (demux->mdatbuffer && demux->n_streams) { 6816 gsize remaining_data_size = 0; 6817 6818 /* the mdat was before the header */ 6819 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p", 6820 demux->n_streams, demux->mdatbuffer); 6821 /* restore our adapter/offset view of things with upstream; 6822 * put preceding buffered data ahead of current moov data. 6823 * This should also handle evil mdat, moov, mdat cases and alike */ 6824 gst_adapter_flush (demux->adapter, demux->neededbytes); 6825 6826 /* Store any remaining data after the mdat for later usage */ 6827 remaining_data_size = gst_adapter_available (demux->adapter); 6828 if (remaining_data_size > 0) { 6829 g_assert (demux->restoredata_buffer == NULL); 6830 demux->restoredata_buffer = 6831 gst_adapter_take_buffer (demux->adapter, remaining_data_size); 6832 demux->restoredata_offset = demux->offset + demux->neededbytes; 6833 GST_DEBUG_OBJECT (demux, 6834 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %" 6835 G_GUINT64_FORMAT, remaining_data_size, 6836 demux->restoredata_offset); 6837 } 6838 6839 gst_adapter_push (demux->adapter, demux->mdatbuffer); 6840 demux->mdatbuffer = NULL; 6841 demux->offset = demux->mdatoffset; 6842 demux->neededbytes = next_entry_size (demux); 6843 demux->state = QTDEMUX_STATE_MOVIE; 6844 demux->mdatleft = gst_adapter_available (demux->adapter); 6845 demux->mdatsize = demux->mdatleft; 6846 } else { 6847 GST_DEBUG_OBJECT (demux, "Carrying on normally"); 6848 gst_adapter_flush (demux->adapter, demux->neededbytes); 6849 6850 /* only go back to the mdat if there are samples to play */ 6851 if (demux->got_moov && demux->first_mdat != -1 6852 && has_next_entry (demux)) { 6853 gboolean res; 6854 6855 /* we need to seek back */ 6856 res = qtdemux_seek_offset (demux, demux->first_mdat); 6857 if (res) { 6858 demux->offset = demux->first_mdat; 6859 } else { 6860 GST_DEBUG_OBJECT (demux, "Seek back failed"); 6861 } 6862 } else { 6863 demux->offset += demux->neededbytes; 6864 } 6865 demux->neededbytes = 16; 6866 demux->state = QTDEMUX_STATE_INITIAL; 6867 } 6868 6869 break; 6870 } 6871 case QTDEMUX_STATE_BUFFER_MDAT:{ 6872 GstBuffer *buf; 6873 guint8 fourcc[4]; 6874 6875 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT, 6876 demux->offset); 6877 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes); 6878 gst_buffer_extract (buf, 0, fourcc, 4); 6879 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT, 6880 GST_FOURCC_ARGS (QT_FOURCC (fourcc))); 6881 if (demux->mdatbuffer) 6882 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf); 6883 else 6884 demux->mdatbuffer = buf; 6885 demux->offset += demux->neededbytes; 6886 demux->neededbytes = 16; 6887 demux->state = QTDEMUX_STATE_INITIAL; 6888 gst_qtdemux_post_progress (demux, 1, 1); 6889 6890 break; 6891 } 6892 case QTDEMUX_STATE_MOVIE:{ 6893 QtDemuxStream *stream = NULL; 6894 QtDemuxSample *sample; 6895 int i = -1; 6896 GstClockTime dts, pts, duration; 6897 gboolean keyframe; 6898 6899 GST_DEBUG_OBJECT (demux, 6900 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset); 6901 6902 if (demux->fragmented) { 6903 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT, 6904 demux->mdatleft); 6905 if (G_LIKELY (demux->todrop < demux->mdatleft)) { 6906 /* if needed data starts within this atom, 6907 * then it should not exceed this atom */ 6908 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) { 6909 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, 6910 (_("This file is invalid and cannot be played.")), 6911 ("sample data crosses atom boundary")); 6912 ret = GST_FLOW_ERROR; 6913 break; 6914 } 6915 demux->mdatleft -= demux->neededbytes; 6916 } else { 6917 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan"); 6918 /* so we are dropping more than left in this atom */ 6919 gst_qtdemux_drop_data (demux, demux->mdatleft); 6920 demux->mdatleft = 0; 6921 6922 /* need to resume atom parsing so we do not miss any other pieces */ 6923 demux->state = QTDEMUX_STATE_INITIAL; 6924 demux->neededbytes = 16; 6925 6926 /* check if there was any stored post mdat data from previous buffers */ 6927 if (demux->restoredata_buffer) { 6928 g_assert (gst_adapter_available (demux->adapter) == 0); 6929 6930 gst_adapter_push (demux->adapter, demux->restoredata_buffer); 6931 demux->restoredata_buffer = NULL; 6932 demux->offset = demux->restoredata_offset; 6933 } 6934 6935 break; 6936 } 6937 } 6938 6939 if (demux->todrop) { 6940 if (demux->cenc_aux_info_offset > 0) { 6941 GstByteReader br; 6942 const guint8 *data; 6943 6944 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info"); 6945 data = gst_adapter_map (demux->adapter, demux->todrop); 6946 gst_byte_reader_init (&br, data + 8, demux->todrop); 6947 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br, 6948 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) { 6949 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info"); 6950 ret = GST_FLOW_ERROR; 6951 gst_adapter_unmap (demux->adapter); 6952 g_free (demux->cenc_aux_info_sizes); 6953 demux->cenc_aux_info_sizes = NULL; 6954 goto done; 6955 } 6956 demux->cenc_aux_info_offset = 0; 6957 g_free (demux->cenc_aux_info_sizes); 6958 demux->cenc_aux_info_sizes = NULL; 6959 gst_adapter_unmap (demux->adapter); 6960 } 6961 gst_qtdemux_drop_data (demux, demux->todrop); 6962 } 6963 6964 /* first buffer? */ 6965 /* initial newsegment sent here after having added pads, 6966 * possible others in sink_event */ 6967 gst_qtdemux_check_send_pending_segment (demux); 6968 6969 /* Figure out which stream this packet belongs to */ 6970 for (i = 0; i < demux->n_streams; i++) { 6971 stream = demux->streams[i]; 6972 if (stream->sample_index >= stream->n_samples) 6973 continue; 6974 GST_LOG_OBJECT (demux, 6975 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT 6976 " / size:%d)", i, stream->sample_index, 6977 stream->samples[stream->sample_index].offset, 6978 stream->samples[stream->sample_index].size); 6979 6980 if (stream->samples[stream->sample_index].offset == demux->offset) 6981 break; 6982 } 6983 6984 if (G_UNLIKELY (stream == NULL || i == demux->n_streams)) 6985 goto unknown_stream; 6986 6987 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream); 6988 6989 if (stream->new_caps) { 6990 gst_qtdemux_configure_stream (demux, stream); 6991 } 6992 6993 /* Put data in a buffer, set timestamps, caps, ... */ 6994 sample = &stream->samples[stream->sample_index]; 6995 6996 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) { 6997 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT, 6998 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc)); 6999 7000 dts = QTSAMPLE_DTS (stream, sample); 7001 pts = QTSAMPLE_PTS (stream, sample); 7002 duration = QTSAMPLE_DUR_DTS (stream, sample, dts); 7003 keyframe = QTSAMPLE_KEYFRAME (stream, sample); 7004 7005 /* check for segment end */ 7006 if (G_UNLIKELY (demux->segment.stop != -1 7007 && demux->segment.stop <= pts && stream->on_keyframe)) { 7008 GST_DEBUG_OBJECT (demux, "we reached the end of our segment."); 7009 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */ 7010 7011 /* skip this data, stream is EOS */ 7012 gst_adapter_flush (demux->adapter, demux->neededbytes); 7013 demux->offset += demux->neededbytes; 7014 7015 /* check if all streams are eos */ 7016 ret = GST_FLOW_EOS; 7017 for (i = 0; i < demux->n_streams; i++) { 7018 if (!STREAM_IS_EOS (demux->streams[i])) { 7019 ret = GST_FLOW_OK; 7020 break; 7021 } 7022 } 7023 } else { 7024 GstBuffer *outbuf; 7025 7026 outbuf = 7027 gst_adapter_take_buffer (demux->adapter, demux->neededbytes); 7028 7029 /* FIXME: should either be an assert or a plain check */ 7030 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR); 7031 7032 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf, 7033 dts, pts, duration, keyframe, dts, demux->offset); 7034 } 7035 7036 /* combine flows */ 7037 ret = gst_qtdemux_combine_flows (demux, stream, ret); 7038 } else { 7039 /* skip this data, stream is EOS */ 7040 gst_adapter_flush (demux->adapter, demux->neededbytes); 7041 } 7042 7043 stream->sample_index++; 7044 stream->offset_in_sample = 0; 7045 7046 /* update current offset and figure out size of next buffer */ 7047 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u", 7048 demux->offset, demux->neededbytes); 7049 demux->offset += demux->neededbytes; 7050 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT, 7051 demux->offset); 7052 7053 7054 if (ret == GST_FLOW_EOS) { 7055 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream"); 7056 demux->neededbytes = -1; 7057 goto eos; 7058 } 7059 7060 if ((demux->neededbytes = next_entry_size (demux)) == -1) { 7061 if (demux->fragmented) { 7062 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples"); 7063 /* there may be more to follow, only finish this atom */ 7064 demux->todrop = demux->mdatleft; 7065 demux->neededbytes = demux->todrop; 7066 break; 7067 } 7068 goto eos; 7069 } 7070 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) { 7071 goto non_ok_unlinked_flow; 7072 } 7073 break; 7074 } 7075 default: 7076 goto invalid_state; 7077 } 7078 } 7079 7080 /* when buffering movie data, at least show user something is happening */ 7081 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT && 7082 gst_adapter_available (demux->adapter) <= demux->neededbytes) { 7083 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter), 7084 demux->neededbytes); 7085 } 7086 done: 7087 7088 return ret; 7089 7090 /* ERRORS */ 7091 non_ok_unlinked_flow: 7092 { 7093 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s", 7094 gst_flow_get_name (ret)); 7095 return ret; 7096 } 7097 unknown_stream: 7098 { 7099 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found")); 7100 ret = GST_FLOW_ERROR; 7101 goto done; 7102 } 7103 eos: 7104 { 7105 GST_DEBUG_OBJECT (demux, "no next entry, EOS"); 7106 ret = GST_FLOW_EOS; 7107 goto done; 7108 } 7109 invalid_state: 7110 { 7111 GST_ELEMENT_ERROR (demux, STREAM, FAILED, 7112 (NULL), ("qtdemuxer invalid state %d", demux->state)); 7113 ret = GST_FLOW_ERROR; 7114 goto done; 7115 } 7116 no_moov: 7117 { 7118 GST_ELEMENT_ERROR (demux, STREAM, FAILED, 7119 (NULL), ("no 'moov' atom within the first 10 MB")); 7120 ret = GST_FLOW_ERROR; 7121 goto done; 7122 } 7123 } 7124 7125 static gboolean 7126 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent) 7127 { 7128 GstQuery *query; 7129 gboolean pull_mode; 7130 7131 query = gst_query_new_scheduling (); 7132 7133 if (!gst_pad_peer_query (sinkpad, query)) { 7134 gst_query_unref (query); 7135 goto activate_push; 7136 } 7137 7138 pull_mode = gst_query_has_scheduling_mode_with_flags (query, 7139 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE); 7140 gst_query_unref (query); 7141 7142 if (!pull_mode) 7143 goto activate_push; 7144 7145 GST_DEBUG_OBJECT (sinkpad, "activating pull"); 7146 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE); 7147 7148 activate_push: 7149 { 7150 GST_DEBUG_OBJECT (sinkpad, "activating push"); 7151 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE); 7152 } 7153 } 7154 7155 static gboolean 7156 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent, 7157 GstPadMode mode, gboolean active) 7158 { 7159 gboolean res; 7160 GstQTDemux *demux = GST_QTDEMUX (parent); 7161 7162 switch (mode) { 7163 case GST_PAD_MODE_PUSH: 7164 demux->pullbased = FALSE; 7165 res = TRUE; 7166 break; 7167 case GST_PAD_MODE_PULL: 7168 if (active) { 7169 demux->pullbased = TRUE; 7170 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop, 7171 sinkpad, NULL); 7172 } else { 7173 res = gst_pad_stop_task (sinkpad); 7174 } 7175 break; 7176 default: 7177 res = FALSE; 7178 break; 7179 } 7180 return res; 7181 } 7182 7183 #ifdef HAVE_ZLIB 7184 static void * 7185 qtdemux_inflate (void *z_buffer, guint z_length, guint * length) 7186 { 7187 guint8 *buffer; 7188 z_stream z; 7189 int ret; 7190 7191 memset (&z, 0, sizeof (z)); 7192 z.zalloc = NULL; 7193 z.zfree = NULL; 7194 z.opaque = NULL; 7195 7196 if ((ret = inflateInit (&z)) != Z_OK) { 7197 GST_ERROR ("inflateInit() returned %d", ret); 7198 return NULL; 7199 } 7200 7201 z.next_in = z_buffer; 7202 z.avail_in = z_length; 7203 7204 buffer = (guint8 *) g_malloc (*length); 7205 z.avail_out = *length; 7206 z.next_out = (Bytef *) buffer; 7207 do { 7208 ret = inflate (&z, Z_NO_FLUSH); 7209 if (ret == Z_STREAM_END) { 7210 break; 7211 } else if (ret != Z_OK) { 7212 GST_WARNING ("inflate() returned %d", ret); 7213 break; 7214 } 7215 7216 *length += 4096; 7217 buffer = (guint8 *) g_realloc (buffer, *length); 7218 z.next_out = (Bytef *) (buffer + z.total_out); 7219 z.avail_out += 4096; 7220 } while (z.avail_in > 0); 7221 7222 if (ret != Z_STREAM_END) { 7223 g_free (buffer); 7224 buffer = NULL; 7225 *length = 0; 7226 } else { 7227 *length = z.total_out; 7228 } 7229 7230 inflateEnd (&z); 7231 7232 return buffer; 7233 } 7234 #endif /* HAVE_ZLIB */ 7235 7236 static gboolean 7237 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length) 7238 { 7239 GNode *cmov; 7240 7241 qtdemux->moov_node = g_node_new ((guint8 *) buffer); 7242 7243 /* counts as header data */ 7244 qtdemux->header_size += length; 7245 7246 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom"); 7247 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length); 7248 7249 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov); 7250 if (cmov) { 7251 guint32 method; 7252 GNode *dcom; 7253 GNode *cmvd; 7254 guint32 dcom_len; 7255 7256 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom); 7257 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd); 7258 if (dcom == NULL || cmvd == NULL) 7259 goto invalid_compression; 7260 7261 dcom_len = QT_UINT32 (dcom->data); 7262 if (dcom_len < 12) 7263 goto invalid_compression; 7264 7265 method = QT_FOURCC ((guint8 *) dcom->data + 8); 7266 switch (method) { 7267 #ifdef HAVE_ZLIB 7268 case FOURCC_zlib:{ 7269 guint uncompressed_length; 7270 guint compressed_length; 7271 guint8 *buf; 7272 guint32 cmvd_len; 7273 7274 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data); 7275 if (cmvd_len < 12) 7276 goto invalid_compression; 7277 7278 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8); 7279 compressed_length = cmvd_len - 12; 7280 GST_LOG ("length = %u", uncompressed_length); 7281 7282 buf = 7283 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12, 7284 compressed_length, &uncompressed_length); 7285 7286 if (buf) { 7287 qtdemux->moov_node_compressed = qtdemux->moov_node; 7288 qtdemux->moov_node = g_node_new (buf); 7289 7290 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf, 7291 uncompressed_length); 7292 } 7293 break; 7294 } 7295 #endif /* HAVE_ZLIB */ 7296 default: 7297 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression " 7298 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method)); 7299 break; 7300 } 7301 } 7302 return TRUE; 7303 7304 /* ERRORS */ 7305 invalid_compression: 7306 { 7307 GST_ERROR_OBJECT (qtdemux, "invalid compressed header"); 7308 return FALSE; 7309 } 7310 } 7311 7312 static gboolean 7313 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf, 7314 const guint8 * end) 7315 { 7316 while (G_UNLIKELY (buf < end)) { 7317 GNode *child; 7318 guint32 len; 7319 7320 if (G_UNLIKELY (buf + 4 > end)) { 7321 GST_LOG_OBJECT (qtdemux, "buffer overrun"); 7322 break; 7323 } 7324 len = QT_UINT32 (buf); 7325 if (G_UNLIKELY (len == 0)) { 7326 GST_LOG_OBJECT (qtdemux, "empty container"); 7327 break; 7328 } 7329 if (G_UNLIKELY (len < 8)) { 7330 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len); 7331 break; 7332 } 7333 if (G_UNLIKELY (len > (end - buf))) { 7334 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len, 7335 (gint) (end - buf)); 7336 break; 7337 } 7338 7339 child = g_node_new ((guint8 *) buf); 7340 g_node_append (node, child); 7341 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len); 7342 qtdemux_parse_node (qtdemux, child, buf, len); 7343 7344 buf += len; 7345 } 7346 return TRUE; 7347 } 7348 7349 static gboolean 7350 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream, 7351 GNode * xdxt) 7352 { 7353 int len = QT_UINT32 (xdxt->data); 7354 guint8 *buf = xdxt->data; 7355 guint8 *end = buf + len; 7356 GstBuffer *buffer; 7357 7358 /* skip size and type */ 7359 buf += 8; 7360 end -= 8; 7361 7362 while (buf < end) { 7363 gint size; 7364 guint32 type; 7365 7366 size = QT_UINT32 (buf); 7367 type = QT_FOURCC (buf + 4); 7368 7369 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end); 7370 7371 if (buf + size > end || size <= 0) 7372 break; 7373 7374 buf += 8; 7375 size -= 8; 7376 7377 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT, 7378 GST_FOURCC_ARGS (type)); 7379 7380 switch (type) { 7381 case FOURCC_tCtH: 7382 buffer = gst_buffer_new_and_alloc (size); 7383 gst_buffer_fill (buffer, 0, buf, size); 7384 stream->buffers = g_slist_append (stream->buffers, buffer); 7385 GST_LOG_OBJECT (qtdemux, "parsing theora header"); 7386 break; 7387 case FOURCC_tCt_: 7388 buffer = gst_buffer_new_and_alloc (size); 7389 gst_buffer_fill (buffer, 0, buf, size); 7390 stream->buffers = g_slist_append (stream->buffers, buffer); 7391 GST_LOG_OBJECT (qtdemux, "parsing theora comment"); 7392 break; 7393 case FOURCC_tCtC: 7394 buffer = gst_buffer_new_and_alloc (size); 7395 gst_buffer_fill (buffer, 0, buf, size); 7396 stream->buffers = g_slist_append (stream->buffers, buffer); 7397 GST_LOG_OBJECT (qtdemux, "parsing theora codebook"); 7398 break; 7399 default: 7400 GST_WARNING_OBJECT (qtdemux, 7401 "unknown theora cookie %" GST_FOURCC_FORMAT, 7402 GST_FOURCC_ARGS (type)); 7403 break; 7404 } 7405 buf += size; 7406 } 7407 return TRUE; 7408 } 7409 7410 static gboolean 7411 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer, 7412 guint length) 7413 { 7414 guint32 fourcc = 0; 7415 guint32 node_length = 0; 7416 const QtNodeType *type; 7417 const guint8 *end; 7418 7419 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length); 7420 7421 if (G_UNLIKELY (length < 8)) 7422 goto not_enough_data; 7423 7424 node_length = QT_UINT32 (buffer); 7425 fourcc = QT_FOURCC (buffer + 4); 7426 7427 /* ignore empty nodes */ 7428 if (G_UNLIKELY (fourcc == 0 || node_length == 8)) 7429 return TRUE; 7430 7431 type = qtdemux_type_get (fourcc); 7432 7433 end = buffer + length; 7434 7435 GST_LOG_OBJECT (qtdemux, 7436 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'", 7437 GST_FOURCC_ARGS (fourcc), node_length, type->name); 7438 7439 if (node_length > length) 7440 goto broken_atom_size; 7441 7442 if (type->flags & QT_FLAG_CONTAINER) { 7443 qtdemux_parse_container (qtdemux, node, buffer + 8, end); 7444 } else { 7445 switch (fourcc) { 7446 case FOURCC_stsd: 7447 { 7448 if (node_length < 20) { 7449 GST_LOG_OBJECT (qtdemux, "skipping small stsd box"); 7450 break; 7451 } 7452 GST_DEBUG_OBJECT (qtdemux, 7453 "parsing stsd (sample table, sample description) atom"); 7454 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */ 7455 qtdemux_parse_container (qtdemux, node, buffer + 16, end); 7456 break; 7457 } 7458 case FOURCC_mp4a: 7459 case FOURCC_alac: 7460 case FOURCC_fLaC: 7461 { 7462 guint32 version; 7463 guint32 offset; 7464 guint min_size; 7465 7466 /* also read alac (or whatever) in stead of mp4a in the following, 7467 * since a similar layout is used in other cases as well */ 7468 if (fourcc == FOURCC_mp4a) 7469 min_size = 20; 7470 else if (fourcc == FOURCC_fLaC) 7471 min_size = 86; 7472 else 7473 min_size = 40; 7474 7475 /* There are two things we might encounter here: a true mp4a atom, and 7476 an mp4a entry in an stsd atom. The latter is what we're interested 7477 in, and it looks like an atom, but isn't really one. The true mp4a 7478 atom is short, so we detect it based on length here. */ 7479 if (length < min_size) { 7480 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box", 7481 GST_FOURCC_ARGS (fourcc)); 7482 break; 7483 } 7484 7485 /* 'version' here is the sound sample description version. Types 0 and 7486 1 are documented in the QTFF reference, but type 2 is not: it's 7487 described in Apple header files instead (struct SoundDescriptionV2 7488 in Movies.h) */ 7489 version = QT_UINT16 (buffer + 16); 7490 7491 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x", 7492 GST_FOURCC_ARGS (fourcc), version); 7493 7494 /* parse any esds descriptors */ 7495 switch (version) { 7496 case 0: 7497 offset = 0x24; 7498 break; 7499 case 1: 7500 offset = 0x34; 7501 break; 7502 case 2: 7503 offset = 0x48; 7504 break; 7505 default: 7506 GST_WARNING_OBJECT (qtdemux, 7507 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x", 7508 GST_FOURCC_ARGS (fourcc), version); 7509 offset = 0; 7510 break; 7511 } 7512 if (offset) 7513 qtdemux_parse_container (qtdemux, node, buffer + offset, end); 7514 break; 7515 } 7516 case FOURCC_mp4v: 7517 case FOURCC_MP4V: 7518 case FOURCC_fmp4: 7519 case FOURCC_FMP4: 7520 case FOURCC_apcs: 7521 case FOURCC_apch: 7522 case FOURCC_apcn: 7523 case FOURCC_apco: 7524 case FOURCC_ap4h: 7525 case FOURCC_xvid: 7526 case FOURCC_XVID: 7527 case FOURCC_H264: 7528 case FOURCC_avc1: 7529 case FOURCC_avc3: 7530 case FOURCC_H265: 7531 case FOURCC_hvc1: 7532 case FOURCC_hev1: 7533 case FOURCC_mjp2: 7534 case FOURCC_encv: 7535 { 7536 guint32 version; 7537 guint32 str_len; 7538 7539 /* codec_data is contained inside these atoms, which all have 7540 * the same format. */ 7541 /* video sample description size is 86 bytes without extension. 7542 * node_length have to be bigger than 86 bytes because video sample 7543 * description can include extenstions such as esds, fiel, glbl, etc. */ 7544 if (node_length < 86) { 7545 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT 7546 " sample description length too short (%u < 86)", 7547 GST_FOURCC_ARGS (fourcc), node_length); 7548 break; 7549 } 7550 7551 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT, 7552 GST_FOURCC_ARGS (fourcc)); 7553 7554 /* version (2 bytes) : this is set to 0, unless a compressor has changed 7555 * its data format. 7556 * revision level (2 bytes) : must be set to 0. */ 7557 version = QT_UINT32 (buffer + 16); 7558 GST_DEBUG_OBJECT (qtdemux, "version %08x", version); 7559 7560 /* compressor name : PASCAL string and informative purposes 7561 * first byte : the number of bytes to be displayed. 7562 * it has to be less than 32 because it is reserved 7563 * space of 32 bytes total including itself. */ 7564 str_len = QT_UINT8 (buffer + 50); 7565 if (str_len < 32) 7566 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len, 7567 (char *) buffer + 51); 7568 else 7569 GST_WARNING_OBJECT (qtdemux, 7570 "compressorname length too big (%u > 31)", str_len); 7571 7572 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer, 7573 end - buffer); 7574 qtdemux_parse_container (qtdemux, node, buffer + 86, end); 7575 break; 7576 } 7577 case FOURCC_meta: 7578 { 7579 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom"); 7580 7581 /* You are reading this correctly. QTFF specifies that the 7582 * metadata atom is a short atom, whereas ISO BMFF specifies 7583 * it's a full atom. But since so many people are doing things 7584 * differently, we actually peek into the atom to see which 7585 * variant it is */ 7586 if (length < 16) { 7587 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box", 7588 GST_FOURCC_ARGS (fourcc)); 7589 break; 7590 } 7591 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) { 7592 /* Variant 1: What QTFF specifies. 'meta' is a short header which 7593 * starts with a 'hdlr' atom */ 7594 qtdemux_parse_container (qtdemux, node, buffer + 8, end); 7595 } else if (QT_UINT32 (buffer + 8) == 0x00000000) { 7596 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom 7597 * with version/flags both set to zero */ 7598 qtdemux_parse_container (qtdemux, node, buffer + 12, end); 7599 } else 7600 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format"); 7601 break; 7602 } 7603 case FOURCC_mp4s: 7604 { 7605 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer); 7606 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */ 7607 qtdemux_parse_container (qtdemux, node, buffer + 16, end); 7608 break; 7609 } 7610 case FOURCC_XiTh: 7611 { 7612 guint32 version; 7613 guint32 offset; 7614 7615 if (length < 16) { 7616 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box", 7617 GST_FOURCC_ARGS (fourcc)); 7618 break; 7619 } 7620 7621 version = QT_UINT32 (buffer + 12); 7622 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version); 7623 7624 switch (version) { 7625 case 0x00000001: 7626 offset = 0x62; 7627 break; 7628 default: 7629 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version); 7630 offset = 0; 7631 break; 7632 } 7633 if (offset) { 7634 if (length < offset) { 7635 GST_WARNING_OBJECT (qtdemux, 7636 "skipping too small %" GST_FOURCC_FORMAT " box", 7637 GST_FOURCC_ARGS (fourcc)); 7638 break; 7639 } 7640 qtdemux_parse_container (qtdemux, node, buffer + offset, end); 7641 } 7642 break; 7643 } 7644 case FOURCC_in24: 7645 { 7646 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end); 7647 break; 7648 } 7649 case FOURCC_uuid: 7650 { 7651 qtdemux_parse_uuid (qtdemux, buffer, end - buffer); 7652 break; 7653 } 7654 case FOURCC_enca: 7655 { 7656 qtdemux_parse_container (qtdemux, node, buffer + 36, end); 7657 break; 7658 } 7659 default: 7660 if (!strcmp (type->name, "unknown")) 7661 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4); 7662 break; 7663 } 7664 } 7665 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'", 7666 GST_FOURCC_ARGS (fourcc)); 7667 return TRUE; 7668 7669 /* ERRORS */ 7670 not_enough_data: 7671 { 7672 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX, 7673 (_("This file is corrupt and cannot be played.")), 7674 ("Not enough data for an atom header, got only %u bytes", length)); 7675 return FALSE; 7676 } 7677 broken_atom_size: 7678 { 7679 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX, 7680 (_("This file is corrupt and cannot be played.")), 7681 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only " 7682 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length, 7683 length)); 7684 return FALSE; 7685 } 7686 } 7687 7688 static GNode * 7689 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc) 7690 { 7691 GNode *child; 7692 guint8 *buffer; 7693 guint32 child_fourcc; 7694 7695 for (child = g_node_first_child (node); child; 7696 child = g_node_next_sibling (child)) { 7697 buffer = (guint8 *) child->data; 7698 7699 child_fourcc = QT_FOURCC (buffer + 4); 7700 7701 if (G_UNLIKELY (child_fourcc == fourcc)) { 7702 return child; 7703 } 7704 } 7705 return NULL; 7706 } 7707 7708 static GNode * 7709 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc, 7710 GstByteReader * parser) 7711 { 7712 GNode *child; 7713 guint8 *buffer; 7714 guint32 child_fourcc, child_len; 7715 7716 for (child = g_node_first_child (node); child; 7717 child = g_node_next_sibling (child)) { 7718 buffer = (guint8 *) child->data; 7719 7720 child_len = QT_UINT32 (buffer); 7721 child_fourcc = QT_FOURCC (buffer + 4); 7722 7723 if (G_UNLIKELY (child_fourcc == fourcc)) { 7724 if (G_UNLIKELY (child_len < (4 + 4))) 7725 return NULL; 7726 /* FIXME: must verify if atom length < parent atom length */ 7727 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4)); 7728 return child; 7729 } 7730 } 7731 return NULL; 7732 } 7733 7734 static GNode * 7735 qtdemux_tree_get_child_by_index (GNode * node, guint index) 7736 { 7737 return g_node_nth_child (node, index); 7738 } 7739 7740 static GNode * 7741 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc, 7742 GstByteReader * parser) 7743 { 7744 GNode *child; 7745 guint8 *buffer; 7746 guint32 child_fourcc, child_len; 7747 7748 for (child = g_node_next_sibling (node); child; 7749 child = g_node_next_sibling (child)) { 7750 buffer = (guint8 *) child->data; 7751 7752 child_fourcc = QT_FOURCC (buffer + 4); 7753 7754 if (child_fourcc == fourcc) { 7755 if (parser) { 7756 child_len = QT_UINT32 (buffer); 7757 if (G_UNLIKELY (child_len < (4 + 4))) 7758 return NULL; 7759 /* FIXME: must verify if atom length < parent atom length */ 7760 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4)); 7761 } 7762 return child; 7763 } 7764 } 7765 return NULL; 7766 } 7767 7768 static GNode * 7769 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc) 7770 { 7771 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL); 7772 } 7773 7774 static void 7775 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream) 7776 { 7777 /* FIXME: This can only reliably work if demuxers have a 7778 * separate streaming thread per srcpad. This should be 7779 * done in a demuxer base class, which integrates parts 7780 * of multiqueue 7781 * 7782 * https://bugzilla.gnome.org/show_bug.cgi?id=701856 7783 */ 7784 #if 0 7785 GstQuery *query; 7786 7787 query = gst_query_new_allocation (stream->caps, FALSE); 7788 7789 if (!gst_pad_peer_query (stream->pad, query)) { 7790 /* not a problem, just debug a little */ 7791 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed"); 7792 } 7793 7794 if (stream->allocator) 7795 gst_object_unref (stream->allocator); 7796 7797 if (gst_query_get_n_allocation_params (query) > 0) { 7798 /* try the allocator */ 7799 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator, 7800 &stream->params); 7801 stream->use_allocator = TRUE; 7802 } else { 7803 stream->allocator = NULL; 7804 gst_allocation_params_init (&stream->params); 7805 stream->use_allocator = FALSE; 7806 } 7807 gst_query_unref (query); 7808 #endif 7809 } 7810 7811 static gboolean 7812 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux, 7813 QtDemuxStream * stream) 7814 { 7815 GstStructure *s; 7816 const gchar *selected_system; 7817 7818 g_return_val_if_fail (qtdemux != NULL, FALSE); 7819 g_return_val_if_fail (stream != NULL, FALSE); 7820 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1, 7821 FALSE); 7822 7823 if (stream->protection_scheme_type != FOURCC_cenc) { 7824 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme"); 7825 return FALSE; 7826 } 7827 if (qtdemux->protection_system_ids == NULL) { 7828 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no " 7829 "cenc protection system information has been found"); 7830 return FALSE; 7831 } 7832 g_ptr_array_add (qtdemux->protection_system_ids, NULL); 7833 selected_system = gst_protection_select_system ((const gchar **) 7834 qtdemux->protection_system_ids->pdata); 7835 g_ptr_array_remove_index (qtdemux->protection_system_ids, 7836 qtdemux->protection_system_ids->len - 1); 7837 if (!selected_system) { 7838 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no " 7839 "suitable decryptor element has been found"); 7840 return FALSE; 7841 } 7842 7843 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0); 7844 if (!gst_structure_has_name (s, "application/x-cenc")) { 7845 gst_structure_set (s, 7846 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), 7847 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system, 7848 NULL); 7849 gst_structure_set_name (s, "application/x-cenc"); 7850 } 7851 return TRUE; 7852 } 7853 7854 static gboolean 7855 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream) 7856 { 7857 if (stream->subtype == FOURCC_vide) { 7858 /* fps is calculated base on the duration of the average framerate since 7859 * qt does not have a fixed framerate. */ 7860 gboolean fps_available = TRUE; 7861 7862 if ((stream->n_samples == 1 && stream->first_duration == 0) 7863 || (qtdemux->fragmented && stream->n_samples_moof == 1)) { 7864 /* still frame */ 7865 CUR_STREAM (stream)->fps_n = 0; 7866 CUR_STREAM (stream)->fps_d = 1; 7867 } else { 7868 if (stream->duration == 0 || stream->n_samples < 2) { 7869 CUR_STREAM (stream)->fps_n = stream->timescale; 7870 CUR_STREAM (stream)->fps_d = 1; 7871 fps_available = FALSE; 7872 } else { 7873 GstClockTime avg_duration; 7874 guint64 duration; 7875 guint32 n_samples; 7876 7877 /* duration and n_samples can be updated for fragmented format 7878 * so, framerate of fragmented format is calculated using data in a moof */ 7879 if (qtdemux->fragmented && stream->n_samples_moof > 0 7880 && stream->duration_moof > 0) { 7881 n_samples = stream->n_samples_moof; 7882 duration = stream->duration_moof; 7883 } else { 7884 n_samples = stream->n_samples; 7885 duration = stream->duration; 7886 } 7887 7888 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */ 7889 /* stream->duration is guint64, timescale, n_samples are guint32 */ 7890 avg_duration = 7891 gst_util_uint64_scale_round (duration - 7892 stream->first_duration, GST_SECOND, 7893 (guint64) (stream->timescale) * (n_samples - 1)); 7894 7895 GST_LOG_OBJECT (qtdemux, 7896 "Calculating avg sample duration based on stream (or moof) duration %" 7897 G_GUINT64_FORMAT 7898 " minus first sample %u, leaving %d samples gives %" 7899 GST_TIME_FORMAT, duration, stream->first_duration, 7900 n_samples - 1, GST_TIME_ARGS (avg_duration)); 7901 7902 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n, 7903 &CUR_STREAM (stream)->fps_d); 7904 7905 GST_DEBUG_OBJECT (qtdemux, 7906 "Calculating framerate, timescale %u gave fps_n %d fps_d %d", 7907 stream->timescale, CUR_STREAM (stream)->fps_n, 7908 CUR_STREAM (stream)->fps_d); 7909 } 7910 } 7911 7912 if (CUR_STREAM (stream)->caps) { 7913 CUR_STREAM (stream)->caps = 7914 gst_caps_make_writable (CUR_STREAM (stream)->caps); 7915 7916 gst_caps_set_simple (CUR_STREAM (stream)->caps, 7917 "width", G_TYPE_INT, CUR_STREAM (stream)->width, 7918 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL); 7919 7920 /* set framerate if calculated framerate is reliable */ 7921 if (fps_available) { 7922 gst_caps_set_simple (CUR_STREAM (stream)->caps, 7923 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n, 7924 CUR_STREAM (stream)->fps_d, NULL); 7925 } 7926 7927 /* calculate pixel-aspect-ratio using display width and height */ 7928 GST_DEBUG_OBJECT (qtdemux, 7929 "video size %dx%d, target display size %dx%d", 7930 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, 7931 stream->display_width, stream->display_height); 7932 /* qt file might have pasp atom */ 7933 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) { 7934 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w, 7935 CUR_STREAM (stream)->par_h); 7936 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio", 7937 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w, 7938 CUR_STREAM (stream)->par_h, NULL); 7939 } else if (stream->display_width > 0 && stream->display_height > 0 7940 && CUR_STREAM (stream)->width > 0 7941 && CUR_STREAM (stream)->height > 0) { 7942 gint n, d; 7943 7944 /* calculate the pixel aspect ratio using the display and pixel w/h */ 7945 n = stream->display_width * CUR_STREAM (stream)->height; 7946 d = stream->display_height * CUR_STREAM (stream)->width; 7947 if (n == d) 7948 n = d = 1; 7949 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d); 7950 CUR_STREAM (stream)->par_w = n; 7951 CUR_STREAM (stream)->par_h = d; 7952 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio", 7953 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w, 7954 CUR_STREAM (stream)->par_h, NULL); 7955 } 7956 7957 if (CUR_STREAM (stream)->interlace_mode > 0) { 7958 if (CUR_STREAM (stream)->interlace_mode == 1) { 7959 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode", 7960 G_TYPE_STRING, "progressive", NULL); 7961 } else if (CUR_STREAM (stream)->interlace_mode == 2) { 7962 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode", 7963 G_TYPE_STRING, "interleaved", NULL); 7964 if (CUR_STREAM (stream)->field_order == 9) { 7965 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order", 7966 G_TYPE_STRING, "top-field-first", NULL); 7967 } else if (CUR_STREAM (stream)->field_order == 14) { 7968 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order", 7969 G_TYPE_STRING, "bottom-field-first", NULL); 7970 } 7971 } 7972 } 7973 7974 /* Create incomplete colorimetry here if needed */ 7975 if (CUR_STREAM (stream)->colorimetry.range || 7976 CUR_STREAM (stream)->colorimetry.matrix || 7977 CUR_STREAM (stream)->colorimetry.transfer 7978 || CUR_STREAM (stream)->colorimetry.primaries) { 7979 gchar *colorimetry = 7980 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry); 7981 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry", 7982 G_TYPE_STRING, colorimetry, NULL); 7983 g_free (colorimetry); 7984 } 7985 7986 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) { 7987 guint par_w = 1, par_h = 1; 7988 7989 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) { 7990 par_w = CUR_STREAM (stream)->par_w; 7991 par_h = CUR_STREAM (stream)->par_h; 7992 } 7993 7994 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode, 7995 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w, 7996 par_h)) { 7997 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT; 7998 } 7999 8000 gst_caps_set_simple (CUR_STREAM (stream)->caps, 8001 "multiview-mode", G_TYPE_STRING, 8002 gst_video_multiview_mode_to_caps_string (stream->multiview_mode), 8003 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, 8004 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL); 8005 } 8006 } 8007 } 8008 8009 else if (stream->subtype == FOURCC_soun) { 8010 if (CUR_STREAM (stream)->caps) { 8011 CUR_STREAM (stream)->caps = 8012 gst_caps_make_writable (CUR_STREAM (stream)->caps); 8013 if (CUR_STREAM (stream)->rate > 0) 8014 gst_caps_set_simple (CUR_STREAM (stream)->caps, 8015 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL); 8016 if (CUR_STREAM (stream)->n_channels > 0) 8017 gst_caps_set_simple (CUR_STREAM (stream)->caps, 8018 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL); 8019 if (CUR_STREAM (stream)->n_channels > 2) { 8020 /* FIXME: Need to parse the 'chan' atom to get channel layouts 8021 * correctly; this is just the minimum we can do - assume 8022 * we don't actually have any channel positions. */ 8023 gst_caps_set_simple (CUR_STREAM (stream)->caps, 8024 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL); 8025 } 8026 } 8027 } 8028 8029 if (stream->pad) { 8030 GstCaps *prev_caps = NULL; 8031 8032 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream; 8033 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event); 8034 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query); 8035 gst_pad_set_active (stream->pad, TRUE); 8036 8037 gst_pad_use_fixed_caps (stream->pad); 8038 8039 if (stream->protected) { 8040 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) { 8041 GST_ERROR_OBJECT (qtdemux, 8042 "Failed to configure protected stream caps."); 8043 return FALSE; 8044 } 8045 } 8046 8047 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, 8048 CUR_STREAM (stream)->caps); 8049 if (stream->new_stream) { 8050 gchar *stream_id; 8051 GstEvent *event; 8052 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE; 8053 8054 event = 8055 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START, 8056 0); 8057 if (event) { 8058 gst_event_parse_stream_flags (event, &stream_flags); 8059 if (gst_event_parse_group_id (event, &qtdemux->group_id)) 8060 qtdemux->have_group_id = TRUE; 8061 else 8062 qtdemux->have_group_id = FALSE; 8063 gst_event_unref (event); 8064 } else if (!qtdemux->have_group_id) { 8065 qtdemux->have_group_id = TRUE; 8066 qtdemux->group_id = gst_util_group_id_next (); 8067 } 8068 8069 stream->new_stream = FALSE; 8070 stream_id = 8071 gst_pad_create_stream_id_printf (stream->pad, 8072 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id); 8073 event = gst_event_new_stream_start (stream_id); 8074 if (qtdemux->have_group_id) 8075 gst_event_set_group_id (event, qtdemux->group_id); 8076 if (stream->disabled) 8077 stream_flags |= GST_STREAM_FLAG_UNSELECT; 8078 if (CUR_STREAM (stream)->sparse) { 8079 stream_flags |= GST_STREAM_FLAG_SPARSE; 8080 } else { 8081 stream_flags &= ~GST_STREAM_FLAG_SPARSE; 8082 } 8083 gst_event_set_stream_flags (event, stream_flags); 8084 gst_pad_push_event (stream->pad, event); 8085 g_free (stream_id); 8086 } 8087 8088 prev_caps = gst_pad_get_current_caps (stream->pad); 8089 8090 if (CUR_STREAM (stream)->caps) { 8091 if (!prev_caps 8092 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) { 8093 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, 8094 CUR_STREAM (stream)->caps); 8095 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps); 8096 } else { 8097 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps"); 8098 } 8099 } else { 8100 GST_WARNING_OBJECT (qtdemux, "stream without caps"); 8101 } 8102 8103 if (prev_caps) 8104 gst_caps_unref (prev_caps); 8105 stream->new_caps = FALSE; 8106 } 8107 return TRUE; 8108 } 8109 8110 static void 8111 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux, 8112 QtDemuxStream * stream) 8113 { 8114 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id) 8115 return; 8116 8117 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'", 8118 stream->cur_stsd_entry_index, stream->stsd_sample_description_id); 8119 if (G_UNLIKELY (stream->stsd_sample_description_id >= 8120 stream->stsd_entries_length)) { 8121 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, 8122 (_("This file is invalid and cannot be played.")), 8123 ("New sample description id is out of bounds (%d >= %d)", 8124 stream->stsd_sample_description_id, stream->stsd_entries_length)); 8125 } else { 8126 stream->cur_stsd_entry_index = stream->stsd_sample_description_id; 8127 stream->new_caps = TRUE; 8128 } 8129 } 8130 8131 static gboolean 8132 gst_qtdemux_add_stream (GstQTDemux * qtdemux, 8133 QtDemuxStream * stream, GstTagList * list) 8134 { 8135 gboolean ret = TRUE; 8136 /* consistent default for push based mode */ 8137 gst_segment_init (&stream->segment, GST_FORMAT_TIME); 8138 8139 if (stream->subtype == FOURCC_vide) { 8140 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams); 8141 8142 stream->pad = 8143 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name); 8144 g_free (name); 8145 8146 if (!gst_qtdemux_configure_stream (qtdemux, stream)) { 8147 gst_object_unref (stream->pad); 8148 stream->pad = NULL; 8149 ret = FALSE; 8150 goto done; 8151 } 8152 8153 qtdemux->n_video_streams++; 8154 } else if (stream->subtype == FOURCC_soun) { 8155 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams); 8156 8157 stream->pad = 8158 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name); 8159 g_free (name); 8160 if (!gst_qtdemux_configure_stream (qtdemux, stream)) { 8161 gst_object_unref (stream->pad); 8162 stream->pad = NULL; 8163 ret = FALSE; 8164 goto done; 8165 } 8166 qtdemux->n_audio_streams++; 8167 } else if (stream->subtype == FOURCC_strm) { 8168 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad"); 8169 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text 8170 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) { 8171 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams); 8172 8173 stream->pad = 8174 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name); 8175 g_free (name); 8176 if (!gst_qtdemux_configure_stream (qtdemux, stream)) { 8177 gst_object_unref (stream->pad); 8178 stream->pad = NULL; 8179 ret = FALSE; 8180 goto done; 8181 } 8182 qtdemux->n_sub_streams++; 8183 } else if (CUR_STREAM (stream)->caps) { 8184 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams); 8185 8186 stream->pad = 8187 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name); 8188 g_free (name); 8189 if (!gst_qtdemux_configure_stream (qtdemux, stream)) { 8190 gst_object_unref (stream->pad); 8191 stream->pad = NULL; 8192 ret = FALSE; 8193 goto done; 8194 } 8195 qtdemux->n_video_streams++; 8196 } else { 8197 GST_DEBUG_OBJECT (qtdemux, "unknown stream type"); 8198 goto done; 8199 } 8200 8201 if (stream->pad) { 8202 GList *l; 8203 #ifdef GSTREAMER_LITE 8204 // Add track_id and track_enabled so we can find this pad later on by track ID 8205 if (CUR_STREAM (stream)->caps) { 8206 gst_caps_set_simple(CUR_STREAM (stream)->caps, 8207 "track_id", G_TYPE_INT, stream->track_id, 8208 "track_enabled", G_TYPE_BOOLEAN, stream->track_enabled, 8209 NULL); 8210 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps); 8211 } 8212 #endif // GSTREAMER_LITE 8213 8214 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p", 8215 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux); 8216 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad); 8217 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad); 8218 8219 if (stream->stream_tags) 8220 gst_tag_list_unref (stream->stream_tags); 8221 stream->stream_tags = list; 8222 list = NULL; 8223 /* global tags go on each pad anyway */ 8224 stream->send_global_tags = TRUE; 8225 /* send upstream GST_EVENT_PROTECTION events that were received before 8226 this source pad was created */ 8227 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next) 8228 gst_pad_push_event (stream->pad, gst_event_ref (l->data)); 8229 } 8230 done: 8231 if (list) 8232 gst_tag_list_unref (list); 8233 return ret; 8234 } 8235 8236 /* find next atom with @fourcc starting at @offset */ 8237 static GstFlowReturn 8238 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset, 8239 guint64 * length, guint32 fourcc) 8240 { 8241 GstFlowReturn ret; 8242 guint32 lfourcc; 8243 GstBuffer *buf; 8244 8245 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %" 8246 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset); 8247 8248 while (TRUE) { 8249 GstMapInfo map; 8250 8251 buf = NULL; 8252 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf); 8253 if (G_UNLIKELY (ret != GST_FLOW_OK)) 8254 goto locate_failed; 8255 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) { 8256 /* likely EOF */ 8257 ret = GST_FLOW_EOS; 8258 gst_buffer_unref (buf); 8259 goto locate_failed; 8260 } 8261 gst_buffer_map (buf, &map, GST_MAP_READ); 8262 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc); 8263 gst_buffer_unmap (buf, &map); 8264 gst_buffer_unref (buf); 8265 8266 if (G_UNLIKELY (*length == 0)) { 8267 GST_DEBUG_OBJECT (qtdemux, "invalid length 0"); 8268 ret = GST_FLOW_ERROR; 8269 goto locate_failed; 8270 } 8271 8272 if (lfourcc == fourcc) { 8273 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT, 8274 *offset); 8275 break; 8276 } else { 8277 GST_LOG_OBJECT (qtdemux, 8278 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT, 8279 GST_FOURCC_ARGS (fourcc), *offset); 8280 *offset += *length; 8281 } 8282 } 8283 8284 return GST_FLOW_OK; 8285 8286 locate_failed: 8287 { 8288 /* might simply have had last one */ 8289 GST_DEBUG_OBJECT (qtdemux, "fourcc not found"); 8290 return ret; 8291 } 8292 } 8293 8294 /* should only do something in pull mode */ 8295 /* call with OBJECT lock */ 8296 static GstFlowReturn 8297 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux) 8298 { 8299 guint64 length, offset; 8300 GstBuffer *buf = NULL; 8301 GstFlowReturn ret = GST_FLOW_OK; 8302 GstFlowReturn res = GST_FLOW_OK; 8303 GstMapInfo map; 8304 8305 offset = qtdemux->moof_offset; 8306 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset); 8307 8308 if (!offset) { 8309 GST_DEBUG_OBJECT (qtdemux, "no next moof"); 8310 return GST_FLOW_EOS; 8311 } 8312 8313 /* best not do pull etc with lock held */ 8314 GST_OBJECT_UNLOCK (qtdemux); 8315 8316 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof); 8317 if (ret != GST_FLOW_OK) 8318 goto flow_failed; 8319 8320 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf); 8321 if (G_UNLIKELY (ret != GST_FLOW_OK)) 8322 goto flow_failed; 8323 gst_buffer_map (buf, &map, GST_MAP_READ); 8324 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) { 8325 gst_buffer_unmap (buf, &map); 8326 gst_buffer_unref (buf); 8327 buf = NULL; 8328 goto parse_failed; 8329 } 8330 8331 gst_buffer_unmap (buf, &map); 8332 gst_buffer_unref (buf); 8333 buf = NULL; 8334 8335 offset += length; 8336 /* look for next moof */ 8337 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof); 8338 if (G_UNLIKELY (ret != GST_FLOW_OK)) 8339 goto flow_failed; 8340 8341 exit: 8342 GST_OBJECT_LOCK (qtdemux); 8343 8344 qtdemux->moof_offset = offset; 8345 8346 return res; 8347 8348 parse_failed: 8349 { 8350 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof"); 8351 offset = 0; 8352 res = GST_FLOW_ERROR; 8353 goto exit; 8354 } 8355 flow_failed: 8356 { 8357 /* maybe upstream temporarily flushing */ 8358 if (ret != GST_FLOW_FLUSHING) { 8359 GST_DEBUG_OBJECT (qtdemux, "no next moof"); 8360 offset = 0; 8361 } else { 8362 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE"); 8363 /* resume at current position next time */ 8364 } 8365 res = ret; 8366 goto exit; 8367 } 8368 } 8369 8370 /* initialise bytereaders for stbl sub-atoms */ 8371 static gboolean 8372 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl) 8373 { 8374 stream->stbl_index = -1; /* no samples have yet been parsed */ 8375 stream->sample_index = -1; 8376 8377 /* time-to-sample atom */ 8378 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts)) 8379 goto corrupt_file; 8380 8381 /* copy atom data into a new buffer for later use */ 8382 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size); 8383 8384 /* skip version + flags */ 8385 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) || 8386 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times)) 8387 goto corrupt_file; 8388 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times); 8389 8390 /* make sure there's enough data */ 8391 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) { 8392 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8; 8393 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks", 8394 stream->n_sample_times); 8395 if (!stream->n_sample_times) 8396 goto corrupt_file; 8397 } 8398 8399 /* sync sample atom */ 8400 stream->stps_present = FALSE; 8401 if ((stream->stss_present = 8402 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss, 8403 &stream->stss) ? TRUE : FALSE) == TRUE) { 8404 /* copy atom data into a new buffer for later use */ 8405 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size); 8406 8407 /* skip version + flags */ 8408 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) || 8409 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs)) 8410 goto corrupt_file; 8411 8412 if (stream->n_sample_syncs) { 8413 /* make sure there's enough data */ 8414 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4)) 8415 goto corrupt_file; 8416 } 8417 8418 /* partial sync sample atom */ 8419 if ((stream->stps_present = 8420 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps, 8421 &stream->stps) ? TRUE : FALSE) == TRUE) { 8422 /* copy atom data into a new buffer for later use */ 8423 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size); 8424 8425 /* skip version + flags */ 8426 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) || 8427 !gst_byte_reader_get_uint32_be (&stream->stps, 8428 &stream->n_sample_partial_syncs)) 8429 goto corrupt_file; 8430 8431 /* if there are no entries, the stss table contains the real 8432 * sync samples */ 8433 if (stream->n_sample_partial_syncs) { 8434 /* make sure there's enough data */ 8435 if (!qt_atom_parser_has_chunks (&stream->stps, 8436 stream->n_sample_partial_syncs, 4)) 8437 goto corrupt_file; 8438 } 8439 } 8440 } 8441 8442 /* sample size */ 8443 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz)) 8444 goto no_samples; 8445 8446 /* copy atom data into a new buffer for later use */ 8447 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size); 8448 8449 /* skip version + flags */ 8450 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) || 8451 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size)) 8452 goto corrupt_file; 8453 8454 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples)) 8455 goto corrupt_file; 8456 8457 if (!stream->n_samples) 8458 goto no_samples; 8459 8460 /* sample-to-chunk atom */ 8461 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc)) 8462 goto corrupt_file; 8463 8464 /* copy atom data into a new buffer for later use */ 8465 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size); 8466 8467 /* skip version + flags */ 8468 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) || 8469 !gst_byte_reader_get_uint32_be (&stream->stsc, 8470 &stream->n_samples_per_chunk)) 8471 goto corrupt_file; 8472 8473 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u", 8474 stream->n_samples_per_chunk); 8475 8476 /* make sure there's enough data */ 8477 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk, 8478 12)) 8479 goto corrupt_file; 8480 8481 8482 /* chunk offset */ 8483 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco)) 8484 stream->co_size = sizeof (guint32); 8485 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64, 8486 &stream->stco)) 8487 stream->co_size = sizeof (guint64); 8488 else 8489 goto corrupt_file; 8490 8491 /* copy atom data into a new buffer for later use */ 8492 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size); 8493 8494 /* skip version + flags */ 8495 if (!gst_byte_reader_skip (&stream->stco, 1 + 3)) 8496 goto corrupt_file; 8497 8498 /* chunks_are_samples == TRUE means treat chunks as samples */ 8499 stream->chunks_are_samples = stream->sample_size 8500 && !CUR_STREAM (stream)->sampled; 8501 if (stream->chunks_are_samples) { 8502 /* treat chunks as samples */ 8503 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples)) 8504 goto corrupt_file; 8505 } else { 8506 /* skip number of entries */ 8507 if (!gst_byte_reader_skip (&stream->stco, 4)) 8508 goto corrupt_file; 8509 8510 /* make sure there are enough data in the stsz atom */ 8511 if (!stream->sample_size) { 8512 /* different sizes for each sample */ 8513 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4)) 8514 goto corrupt_file; 8515 } 8516 } 8517 8518 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)", 8519 stream->n_samples, (guint) sizeof (QtDemuxSample), 8520 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0)); 8521 8522 if (stream->n_samples >= 8523 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) { 8524 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would " 8525 "be larger than %uMB (broken file?)", stream->n_samples, 8526 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20); 8527 return FALSE; 8528 } 8529 8530 g_assert (stream->samples == NULL); 8531 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples); 8532 if (!stream->samples) { 8533 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples", 8534 stream->n_samples); 8535 return FALSE; 8536 } 8537 8538 /* composition time-to-sample */ 8539 if ((stream->ctts_present = 8540 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts, 8541 &stream->ctts) ? TRUE : FALSE) == TRUE) { 8542 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0); 8543 8544 /* copy atom data into a new buffer for later use */ 8545 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size); 8546 8547 /* skip version + flags */ 8548 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3) 8549 || !gst_byte_reader_get_uint32_be (&stream->ctts, 8550 &stream->n_composition_times)) 8551 goto corrupt_file; 8552 8553 /* make sure there's enough data */ 8554 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times, 8555 4 + 4)) 8556 goto corrupt_file; 8557 8558 /* This is optional, if missing we iterate the ctts */ 8559 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) { 8560 if (!gst_byte_reader_skip (&cslg, 1 + 3) 8561 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) { 8562 g_free ((gpointer) cslg.data); 8563 goto corrupt_file; 8564 } 8565 } else { 8566 gint32 cslg_least = 0; 8567 guint num_entries, pos; 8568 gint i; 8569 8570 pos = gst_byte_reader_get_pos (&stream->ctts); 8571 num_entries = stream->n_composition_times; 8572 8573 stream->cslg_shift = 0; 8574 8575 for (i = 0; i < num_entries; i++) { 8576 gint32 offset; 8577 8578 gst_byte_reader_skip_unchecked (&stream->ctts, 4); 8579 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts); 8580 8581 if (offset < cslg_least) 8582 cslg_least = offset; 8583 } 8584 8585 if (cslg_least < 0) 8586 stream->cslg_shift = ABS (cslg_least); 8587 else 8588 stream->cslg_shift = 0; 8589 8590 /* reset the reader so we can generate sample table */ 8591 gst_byte_reader_set_pos (&stream->ctts, pos); 8592 } 8593 } else { 8594 /* Ensure the cslg_shift value is consistent so we can use it 8595 * unconditionnally to produce TS and Segment */ 8596 stream->cslg_shift = 0; 8597 } 8598 8599 return TRUE; 8600 8601 corrupt_file: 8602 { 8603 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX, 8604 (_("This file is corrupt and cannot be played.")), (NULL)); 8605 return FALSE; 8606 } 8607 no_samples: 8608 { 8609 gst_qtdemux_stbl_free (stream); 8610 if (!qtdemux->fragmented) { 8611 /* not quite good */ 8612 GST_WARNING_OBJECT (qtdemux, "stream has no samples"); 8613 return FALSE; 8614 } else { 8615 /* may pick up samples elsewhere */ 8616 return TRUE; 8617 } 8618 } 8619 } 8620 8621 /* collect samples from the next sample to be parsed up to sample @n for @stream 8622 * by reading the info from @stbl 8623 * 8624 * This code can be executed from both the streaming thread and the seeking 8625 * thread so it takes the object lock to protect itself 8626 */ 8627 static gboolean 8628 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n) 8629 { 8630 gint i, j, k; 8631 QtDemuxSample *samples, *first, *cur, *last; 8632 guint32 n_samples_per_chunk; 8633 guint32 n_samples; 8634 8635 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %" 8636 GST_FOURCC_FORMAT ", pad %s", 8637 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc), 8638 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)"); 8639 8640 n_samples = stream->n_samples; 8641 8642 if (n >= n_samples) 8643 goto out_of_samples; 8644 8645 GST_OBJECT_LOCK (qtdemux); 8646 if (n <= stream->stbl_index) 8647 goto already_parsed; 8648 8649 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n); 8650 8651 if (!stream->stsz.data) { 8652 /* so we already parsed and passed all the moov samples; 8653 * onto fragmented ones */ 8654 g_assert (qtdemux->fragmented); 8655 goto done; 8656 } 8657 8658 /* pointer to the sample table */ 8659 samples = stream->samples; 8660 8661 /* starts from -1, moves to the next sample index to parse */ 8662 stream->stbl_index++; 8663 8664 /* keep track of the first and last sample to fill */ 8665 first = &samples[stream->stbl_index]; 8666 last = &samples[n]; 8667 8668 if (!stream->chunks_are_samples) { 8669 /* set the sample sizes */ 8670 if (stream->sample_size == 0) { 8671 /* different sizes for each sample */ 8672 for (cur = first; cur <= last; cur++) { 8673 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz); 8674 GST_LOG_OBJECT (qtdemux, "sample %d has size %u", 8675 (guint) (cur - samples), cur->size); 8676 } 8677 } else { 8678 /* samples have the same size */ 8679 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size); 8680 for (cur = first; cur <= last; cur++) 8681 cur->size = stream->sample_size; 8682 } 8683 } 8684 8685 n_samples_per_chunk = stream->n_samples_per_chunk; 8686 cur = first; 8687 8688 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) { 8689 guint32 last_chunk; 8690 8691 if (stream->stsc_chunk_index >= stream->last_chunk 8692 || stream->stsc_chunk_index < stream->first_chunk) { 8693 stream->first_chunk = 8694 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc); 8695 stream->samples_per_chunk = 8696 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc); 8697 /* starts from 1 */ 8698 stream->stsd_sample_description_id = 8699 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1; 8700 8701 /* chunk numbers are counted from 1 it seems */ 8702 if (G_UNLIKELY (stream->first_chunk == 0)) 8703 goto corrupt_file; 8704 8705 --stream->first_chunk; 8706 8707 /* the last chunk of each entry is calculated by taking the first chunk 8708 * of the next entry; except if there is no next, where we fake it with 8709 * INT_MAX */ 8710 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) { 8711 stream->last_chunk = G_MAXUINT32; 8712 } else { 8713 stream->last_chunk = 8714 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc); 8715 if (G_UNLIKELY (stream->last_chunk == 0)) 8716 goto corrupt_file; 8717 8718 --stream->last_chunk; 8719 } 8720 8721 GST_LOG_OBJECT (qtdemux, 8722 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d" 8723 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk, 8724 stream->samples_per_chunk, stream->stsd_sample_description_id); 8725 8726 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk)) 8727 goto corrupt_file; 8728 8729 if (stream->last_chunk != G_MAXUINT32) { 8730 if (!qt_atom_parser_peek_sub (&stream->stco, 8731 stream->first_chunk * stream->co_size, 8732 (stream->last_chunk - stream->first_chunk) * stream->co_size, 8733 &stream->co_chunk)) 8734 goto corrupt_file; 8735 8736 } else { 8737 stream->co_chunk = stream->stco; 8738 if (!gst_byte_reader_skip (&stream->co_chunk, 8739 stream->first_chunk * stream->co_size)) 8740 goto corrupt_file; 8741 } 8742 8743 stream->stsc_chunk_index = stream->first_chunk; 8744 } 8745 8746 last_chunk = stream->last_chunk; 8747 8748 if (stream->chunks_are_samples) { 8749 cur = &samples[stream->stsc_chunk_index]; 8750 8751 for (j = stream->stsc_chunk_index; j < last_chunk; j++) { 8752 if (j > n) { 8753 /* save state */ 8754 stream->stsc_chunk_index = j; 8755 goto done; 8756 } 8757 8758 cur->offset = 8759 qt_atom_parser_get_offset_unchecked (&stream->co_chunk, 8760 stream->co_size); 8761 8762 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset " 8763 "%" G_GUINT64_FORMAT, j, cur->offset); 8764 8765 if (CUR_STREAM (stream)->samples_per_frame > 0 && 8766 CUR_STREAM (stream)->bytes_per_frame > 0) { 8767 cur->size = 8768 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) / 8769 CUR_STREAM (stream)->samples_per_frame * 8770 CUR_STREAM (stream)->bytes_per_frame; 8771 } else { 8772 cur->size = stream->samples_per_chunk; 8773 } 8774 8775 GST_DEBUG_OBJECT (qtdemux, 8776 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u", 8777 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, 8778 stream->stco_sample_index)), cur->size); 8779 8780 cur->timestamp = stream->stco_sample_index; 8781 cur->duration = stream->samples_per_chunk; 8782 cur->keyframe = TRUE; 8783 cur++; 8784 8785 stream->stco_sample_index += stream->samples_per_chunk; 8786 } 8787 stream->stsc_chunk_index = j; 8788 } else { 8789 for (j = stream->stsc_chunk_index; j < last_chunk; j++) { 8790 guint32 samples_per_chunk; 8791 guint64 chunk_offset; 8792 8793 if (!stream->stsc_sample_index 8794 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size, 8795 &stream->chunk_offset)) 8796 goto corrupt_file; 8797 8798 samples_per_chunk = stream->samples_per_chunk; 8799 chunk_offset = stream->chunk_offset; 8800 8801 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) { 8802 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %" 8803 G_GUINT64_FORMAT " and size %d", 8804 (guint) (cur - samples), chunk_offset, cur->size); 8805 8806 cur->offset = chunk_offset; 8807 chunk_offset += cur->size; 8808 cur++; 8809 8810 if (G_UNLIKELY (cur > last)) { 8811 /* save state */ 8812 stream->stsc_sample_index = k + 1; 8813 stream->chunk_offset = chunk_offset; 8814 stream->stsc_chunk_index = j; 8815 goto done2; 8816 } 8817 } 8818 stream->stsc_sample_index = 0; 8819 } 8820 stream->stsc_chunk_index = j; 8821 } 8822 stream->stsc_index++; 8823 } 8824 8825 if (stream->chunks_are_samples) 8826 goto ctts; 8827 done2: 8828 { 8829 guint32 n_sample_times; 8830 8831 n_sample_times = stream->n_sample_times; 8832 cur = first; 8833 8834 for (i = stream->stts_index; i < n_sample_times; i++) { 8835 guint32 stts_samples; 8836 gint32 stts_duration; 8837 gint64 stts_time; 8838 8839 if (stream->stts_sample_index >= stream->stts_samples 8840 || !stream->stts_sample_index) { 8841 8842 stream->stts_samples = 8843 gst_byte_reader_get_uint32_be_unchecked (&stream->stts); 8844 stream->stts_duration = 8845 gst_byte_reader_get_uint32_be_unchecked (&stream->stts); 8846 8847 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u", 8848 i, stream->stts_samples, stream->stts_duration); 8849 8850 stream->stts_sample_index = 0; 8851 } 8852 8853 stts_samples = stream->stts_samples; 8854 stts_duration = stream->stts_duration; 8855 stts_time = stream->stts_time; 8856 8857 for (j = stream->stts_sample_index; j < stts_samples; j++) { 8858 GST_DEBUG_OBJECT (qtdemux, 8859 "sample %d: index %d, timestamp %" GST_TIME_FORMAT, 8860 (guint) (cur - samples), j, 8861 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time))); 8862 8863 cur->timestamp = stts_time; 8864 cur->duration = stts_duration; 8865 8866 /* avoid 32-bit wrap-around, 8867 * but still mind possible 'negative' duration */ 8868 stts_time += (gint64) stts_duration; 8869 cur++; 8870 8871 if (G_UNLIKELY (cur > last)) { 8872 /* save values */ 8873 stream->stts_time = stts_time; 8874 stream->stts_sample_index = j + 1; 8875 if (stream->stts_sample_index >= stream->stts_samples) 8876 stream->stts_index++; 8877 goto done3; 8878 } 8879 } 8880 stream->stts_sample_index = 0; 8881 stream->stts_time = stts_time; 8882 stream->stts_index++; 8883 } 8884 /* fill up empty timestamps with the last timestamp, this can happen when 8885 * the last samples do not decode and so we don't have timestamps for them. 8886 * We however look at the last timestamp to estimate the track length so we 8887 * need something in here. */ 8888 for (; cur < last; cur++) { 8889 GST_DEBUG_OBJECT (qtdemux, 8890 "fill sample %d: timestamp %" GST_TIME_FORMAT, 8891 (guint) (cur - samples), 8892 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time))); 8893 cur->timestamp = stream->stts_time; 8894 cur->duration = -1; 8895 } 8896 } 8897 done3: 8898 { 8899 /* sample sync, can be NULL */ 8900 if (stream->stss_present == TRUE) { 8901 guint32 n_sample_syncs; 8902 8903 n_sample_syncs = stream->n_sample_syncs; 8904 8905 if (!n_sample_syncs) { 8906 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes"); 8907 stream->all_keyframe = TRUE; 8908 } else { 8909 for (i = stream->stss_index; i < n_sample_syncs; i++) { 8910 /* note that the first sample is index 1, not 0 */ 8911 guint32 index; 8912 8913 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss); 8914 8915 if (G_LIKELY (index > 0 && index <= n_samples)) { 8916 index -= 1; 8917 samples[index].keyframe = TRUE; 8918 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index); 8919 /* and exit if we have enough samples */ 8920 if (G_UNLIKELY (index >= n)) { 8921 i++; 8922 break; 8923 } 8924 } 8925 } 8926 /* save state */ 8927 stream->stss_index = i; 8928 } 8929 8930 /* stps marks partial sync frames like open GOP I-Frames */ 8931 if (stream->stps_present == TRUE) { 8932 guint32 n_sample_partial_syncs; 8933 8934 n_sample_partial_syncs = stream->n_sample_partial_syncs; 8935 8936 /* if there are no entries, the stss table contains the real 8937 * sync samples */ 8938 if (n_sample_partial_syncs) { 8939 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) { 8940 /* note that the first sample is index 1, not 0 */ 8941 guint32 index; 8942 8943 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps); 8944 8945 if (G_LIKELY (index > 0 && index <= n_samples)) { 8946 index -= 1; 8947 samples[index].keyframe = TRUE; 8948 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index); 8949 /* and exit if we have enough samples */ 8950 if (G_UNLIKELY (index >= n)) { 8951 i++; 8952 break; 8953 } 8954 } 8955 } 8956 /* save state */ 8957 stream->stps_index = i; 8958 } 8959 } 8960 } else { 8961 /* no stss, all samples are keyframes */ 8962 stream->all_keyframe = TRUE; 8963 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes"); 8964 } 8965 } 8966 8967 ctts: 8968 /* composition time to sample */ 8969 if (stream->ctts_present == TRUE) { 8970 guint32 n_composition_times; 8971 guint32 ctts_count; 8972 gint32 ctts_soffset; 8973 8974 /* Fill in the pts_offsets */ 8975 cur = first; 8976 n_composition_times = stream->n_composition_times; 8977 8978 for (i = stream->ctts_index; i < n_composition_times; i++) { 8979 if (stream->ctts_sample_index >= stream->ctts_count 8980 || !stream->ctts_sample_index) { 8981 stream->ctts_count = 8982 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts); 8983 stream->ctts_soffset = 8984 gst_byte_reader_get_int32_be_unchecked (&stream->ctts); 8985 stream->ctts_sample_index = 0; 8986 } 8987 8988 ctts_count = stream->ctts_count; 8989 ctts_soffset = stream->ctts_soffset; 8990 8991 for (j = stream->ctts_sample_index; j < ctts_count; j++) { 8992 cur->pts_offset = ctts_soffset; 8993 cur++; 8994 8995 if (G_UNLIKELY (cur > last)) { 8996 /* save state */ 8997 stream->ctts_sample_index = j + 1; 8998 goto done; 8999 } 9000 } 9001 stream->ctts_sample_index = 0; 9002 stream->ctts_index++; 9003 } 9004 } 9005 done: 9006 stream->stbl_index = n; 9007 /* if index has been completely parsed, free data that is no-longer needed */ 9008 if (n + 1 == stream->n_samples) { 9009 gst_qtdemux_stbl_free (stream); 9010 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;"); 9011 if (qtdemux->pullbased) { 9012 GST_DEBUG_OBJECT (qtdemux, "checking for more samples"); 9013 while (n + 1 == stream->n_samples) 9014 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK) 9015 break; 9016 } 9017 } 9018 GST_OBJECT_UNLOCK (qtdemux); 9019 9020 return TRUE; 9021 9022 /* SUCCESS */ 9023 already_parsed: 9024 { 9025 GST_LOG_OBJECT (qtdemux, 9026 "Tried to parse up to sample %u but this sample has already been parsed", 9027 n); 9028 /* if fragmented, there may be more */ 9029 if (qtdemux->fragmented && n == stream->stbl_index) 9030 goto done; 9031 GST_OBJECT_UNLOCK (qtdemux); 9032 return TRUE; 9033 } 9034 /* ERRORS */ 9035 out_of_samples: 9036 { 9037 GST_LOG_OBJECT (qtdemux, 9038 "Tried to parse up to sample %u but there are only %u samples", n + 1, 9039 stream->n_samples); 9040 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX, 9041 (_("This file is corrupt and cannot be played.")), (NULL)); 9042 return FALSE; 9043 } 9044 corrupt_file: 9045 { 9046 GST_OBJECT_UNLOCK (qtdemux); 9047 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX, 9048 (_("This file is corrupt and cannot be played.")), (NULL)); 9049 return FALSE; 9050 } 9051 } 9052 9053 /* collect all segment info for @stream. 9054 */ 9055 static gboolean 9056 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream, 9057 GNode * trak) 9058 { 9059 GNode *edts; 9060 /* accept edts if they contain gaps at start and there is only 9061 * one media segment */ 9062 gboolean allow_pushbased_edts = TRUE; 9063 gint media_segments_count = 0; 9064 9065 /* parse and prepare segment info from the edit list */ 9066 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container"); 9067 stream->n_segments = 0; 9068 stream->segments = NULL; 9069 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) { 9070 GNode *elst; 9071 gint n_segments; 9072 gint i, count, entry_size; 9073 guint64 time; 9074 GstClockTime stime; 9075 const guint8 *buffer; 9076 guint8 version; 9077 guint32 size; 9078 9079 GST_DEBUG_OBJECT (qtdemux, "looking for edit list"); 9080 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst))) 9081 goto done; 9082 9083 buffer = elst->data; 9084 9085 size = QT_UINT32 (buffer); 9086 /* version, flags, n_segments */ 9087 if (size < 16) { 9088 GST_WARNING_OBJECT (qtdemux, "Invalid edit list"); 9089 goto done; 9090 } 9091 version = QT_UINT8 (buffer + 8); 9092 entry_size = (version == 1) ? 20 : 12; 9093 9094 n_segments = QT_UINT32 (buffer + 12); 9095 9096 if (n_segments > 100000 || size < 16 + n_segments * entry_size) { 9097 GST_WARNING_OBJECT (qtdemux, "Invalid edit list"); 9098 goto done; 9099 } 9100 9101 /* we might allocate a bit too much, at least allocate 1 segment */ 9102 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1)); 9103 9104 /* segments always start from 0 */ 9105 time = 0; 9106 stime = 0; 9107 count = 0; 9108 buffer += 16; 9109 for (i = 0; i < n_segments; i++) { 9110 guint64 duration; 9111 guint64 media_time; 9112 gboolean time_valid = TRUE; 9113 QtDemuxSegment *segment; 9114 guint32 rate_int; 9115 GstClockTime media_start = GST_CLOCK_TIME_NONE; 9116 9117 if (version == 1) { 9118 media_time = QT_UINT64 (buffer + 8); 9119 duration = QT_UINT64 (buffer); 9120 if (media_time == G_MAXUINT64) 9121 time_valid = FALSE; 9122 } else { 9123 media_time = QT_UINT32 (buffer + 4); 9124 duration = QT_UINT32 (buffer); 9125 if (media_time == G_MAXUINT32) 9126 time_valid = FALSE; 9127 } 9128 9129 if (time_valid) 9130 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time); 9131 9132 segment = &stream->segments[count++]; 9133 9134 /* time and duration expressed in global timescale */ 9135 segment->time = stime; 9136 /* add non scaled values so we don't cause roundoff errors */ 9137 if (duration || media_start == GST_CLOCK_TIME_NONE) { 9138 time += duration; 9139 stime = QTTIME_TO_GSTTIME (qtdemux, time); 9140 segment->duration = stime - segment->time; 9141 } else { 9142 /* zero duration does not imply media_start == media_stop 9143 * but, only specify media_start.*/ 9144 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration); 9145 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid 9146 && stime >= media_start) { 9147 segment->duration = stime - media_start; 9148 } else { 9149 segment->duration = GST_CLOCK_TIME_NONE; 9150 } 9151 } 9152 segment->stop_time = stime; 9153 9154 segment->trak_media_start = media_time; 9155 /* media_time expressed in stream timescale */ 9156 if (time_valid) { 9157 segment->media_start = media_start; 9158 segment->media_stop = segment->media_start + segment->duration; 9159 media_segments_count++; 9160 } else { 9161 segment->media_start = GST_CLOCK_TIME_NONE; 9162 segment->media_stop = GST_CLOCK_TIME_NONE; 9163 } 9164 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8)); 9165 9166 if (rate_int <= 1) { 9167 /* 0 is not allowed, some programs write 1 instead of the floating point 9168 * value */ 9169 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT, 9170 rate_int); 9171 segment->rate = 1; 9172 } else { 9173 segment->rate = rate_int / 65536.0; 9174 } 9175 9176 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT 9177 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT 9178 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT 9179 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u", 9180 i, GST_TIME_ARGS (segment->time), 9181 GST_TIME_ARGS (segment->duration), 9182 GST_TIME_ARGS (segment->media_start), media_time, 9183 GST_TIME_ARGS (segment->media_stop), 9184 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int, 9185 stream->timescale); 9186 if (segment->stop_time > qtdemux->segment.stop) { 9187 GST_WARNING_OBJECT (qtdemux, "Segment %d " 9188 " extends to %" GST_TIME_FORMAT 9189 " past the end of the file duration %" GST_TIME_FORMAT 9190 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time), 9191 GST_TIME_ARGS (qtdemux->segment.stop)); 9192 qtdemux->segment.stop = segment->stop_time; 9193 } 9194 9195 buffer += entry_size; 9196 } 9197 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count); 9198 stream->n_segments = count; 9199 if (media_segments_count != 1) 9200 allow_pushbased_edts = FALSE; 9201 } 9202 done: 9203 9204 /* push based does not handle segments, so act accordingly here, 9205 * and warn if applicable */ 9206 if (!qtdemux->pullbased && !allow_pushbased_edts) { 9207 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments"); 9208 /* remove and use default one below, we stream like it anyway */ 9209 g_free (stream->segments); 9210 stream->segments = NULL; 9211 stream->n_segments = 0; 9212 } 9213 9214 /* no segments, create one to play the complete trak */ 9215 if (stream->n_segments == 0) { 9216 GstClockTime stream_duration = 9217 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration); 9218 9219 if (stream->segments == NULL) 9220 stream->segments = g_new (QtDemuxSegment, 1); 9221 9222 /* represent unknown our way */ 9223 if (stream_duration == 0) 9224 stream_duration = GST_CLOCK_TIME_NONE; 9225 9226 stream->segments[0].time = 0; 9227 stream->segments[0].stop_time = stream_duration; 9228 stream->segments[0].duration = stream_duration; 9229 stream->segments[0].media_start = 0; 9230 stream->segments[0].media_stop = stream_duration; 9231 stream->segments[0].rate = 1.0; 9232 stream->segments[0].trak_media_start = 0; 9233 9234 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT, 9235 GST_TIME_ARGS (stream_duration)); 9236 stream->n_segments = 1; 9237 stream->dummy_segment = TRUE; 9238 } 9239 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments); 9240 9241 return TRUE; 9242 } 9243 9244 /* 9245 * Parses the stsd atom of a svq3 trak looking for 9246 * the SMI and gama atoms. 9247 */ 9248 static void 9249 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, 9250 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh) 9251 { 9252 const guint8 *_gamma = NULL; 9253 GstBuffer *_seqh = NULL; 9254 const guint8 *stsd_data = stsd_entry_data; 9255 guint32 length = QT_UINT32 (stsd_data); 9256 guint16 version; 9257 9258 if (length < 32) { 9259 GST_WARNING_OBJECT (qtdemux, "stsd too short"); 9260 goto end; 9261 } 9262 9263 stsd_data += 16; 9264 length -= 16; 9265 version = QT_UINT16 (stsd_data); 9266 if (version == 3) { 9267 if (length >= 70) { 9268 length -= 70; 9269 stsd_data += 70; 9270 while (length > 8) { 9271 guint32 fourcc, size; 9272 const guint8 *data; 9273 size = QT_UINT32 (stsd_data); 9274 fourcc = QT_FOURCC (stsd_data + 4); 9275 data = stsd_data + 8; 9276 9277 if (size == 0) { 9278 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting " 9279 "svq3 atom parsing"); 9280 goto end; 9281 } 9282 9283 switch (fourcc) { 9284 case FOURCC_gama:{ 9285 if (size == 12) { 9286 _gamma = data; 9287 } else { 9288 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT 9289 " for gama atom, expected 12", size); 9290 } 9291 break; 9292 } 9293 case FOURCC_SMI_:{ 9294 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) { 9295 guint32 seqh_size; 9296 if (_seqh != NULL) { 9297 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom " 9298 " found, ignoring"); 9299 } else { 9300 seqh_size = QT_UINT32 (data + 4); 9301 if (seqh_size > 0) { 9302 _seqh = gst_buffer_new_and_alloc (seqh_size); 9303 gst_buffer_fill (_seqh, 0, data + 8, seqh_size); 9304 } 9305 } 9306 } 9307 break; 9308 } 9309 default:{ 9310 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT 9311 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc)); 9312 } 9313 } 9314 9315 if (size <= length) { 9316 length -= size; 9317 stsd_data += size; 9318 } 9319 } 9320 } else { 9321 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom"); 9322 } 9323 } else { 9324 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %" 9325 G_GUINT16_FORMAT, version); 9326 goto end; 9327 } 9328 9329 end: 9330 if (gamma) { 9331 *gamma = _gamma; 9332 } 9333 if (seqh) { 9334 *seqh = _seqh; 9335 } else if (_seqh) { 9336 gst_buffer_unref (_seqh); 9337 } 9338 } 9339 9340 static gchar * 9341 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf) 9342 { 9343 GNode *dinf; 9344 GstByteReader dref; 9345 gchar *uri = NULL; 9346 9347 /* 9348 * Get 'dinf', to get its child 'dref', that might contain a 'hndl' 9349 * atom that might contain a 'data' atom with the rtsp uri. 9350 * This case was reported in bug #597497, some info about 9351 * the hndl atom can be found in TN1195 9352 */ 9353 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf); 9354 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak"); 9355 9356 if (dinf) { 9357 guint32 dref_num_entries = 0; 9358 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) && 9359 gst_byte_reader_skip (&dref, 4) && 9360 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) { 9361 gint i; 9362 9363 /* search dref entries for hndl atom */ 9364 for (i = 0; i < dref_num_entries; i++) { 9365 guint32 size = 0, type; 9366 guint8 string_len = 0; 9367 if (gst_byte_reader_get_uint32_be (&dref, &size) && 9368 qt_atom_parser_get_fourcc (&dref, &type)) { 9369 if (type == FOURCC_hndl) { 9370 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom"); 9371 9372 /* skip data reference handle bytes and the 9373 * following pascal string and some extra 4 9374 * bytes I have no idea what are */ 9375 if (!gst_byte_reader_skip (&dref, 4) || 9376 !gst_byte_reader_get_uint8 (&dref, &string_len) || 9377 !gst_byte_reader_skip (&dref, string_len + 4)) { 9378 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom"); 9379 break; 9380 } 9381 9382 /* iterate over the atoms to find the data atom */ 9383 while (gst_byte_reader_get_remaining (&dref) >= 8) { 9384 guint32 atom_size; 9385 guint32 atom_type; 9386 9387 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) && 9388 qt_atom_parser_get_fourcc (&dref, &atom_type)) { 9389 if (atom_type == FOURCC_data) { 9390 const guint8 *uri_aux = NULL; 9391 9392 /* found the data atom that might contain the rtsp uri */ 9393 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside " 9394 "hndl atom, interpreting it as an URI"); 9395 if (gst_byte_reader_peek_data (&dref, atom_size - 8, 9396 &uri_aux)) { 9397 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL) 9398 uri = g_strndup ((gchar *) uri_aux, atom_size - 8); 9399 else 9400 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom " 9401 "didn't contain a rtsp address"); 9402 } else { 9403 GST_WARNING_OBJECT (qtdemux, "Failed to get the data " 9404 "atom contents"); 9405 } 9406 break; 9407 } 9408 /* skipping to the next entry */ 9409 if (!gst_byte_reader_skip (&dref, atom_size - 8)) 9410 break; 9411 } else { 9412 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child " 9413 "atom header"); 9414 break; 9415 } 9416 } 9417 break; 9418 } 9419 /* skip to the next entry */ 9420 if (!gst_byte_reader_skip (&dref, size - 8)) 9421 break; 9422 } else { 9423 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom"); 9424 } 9425 } 9426 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom"); 9427 } 9428 } 9429 return uri; 9430 } 9431 9432 #define AMR_NB_ALL_MODES 0x81ff 9433 #define AMR_WB_ALL_MODES 0x83ff 9434 static guint 9435 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb) 9436 { 9437 /* The 'damr' atom is of the form: 9438 * 9439 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample | 9440 * 32 b 8 b 16 b 8 b 8 b 9441 * 9442 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set 9443 * represents the highest mode used in the stream (and thus the maximum 9444 * bitrate), with a couple of special cases as seen below. 9445 */ 9446 9447 /* Map of frame type ID -> bitrate */ 9448 static const guint nb_bitrates[] = { 9449 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200 9450 }; 9451 static const guint wb_bitrates[] = { 9452 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850 9453 }; 9454 GstMapInfo map; 9455 gsize max_mode; 9456 guint16 mode_set; 9457 9458 gst_buffer_map (buf, &map, GST_MAP_READ); 9459 9460 if (map.size != 0x11) { 9461 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size); 9462 goto bad_data; 9463 } 9464 9465 if (QT_FOURCC (map.data + 4) != FOURCC_damr) { 9466 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT, 9467 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4))); 9468 goto bad_data; 9469 } 9470 9471 mode_set = QT_UINT16 (map.data + 13); 9472 9473 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES)) 9474 max_mode = 7 + (wb ? 1 : 0); 9475 else 9476 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */ 9477 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1); 9478 9479 if (max_mode == -1) { 9480 GST_DEBUG ("No mode indication was found (mode set) = %x", 9481 (guint) mode_set); 9482 goto bad_data; 9483 } 9484 9485 gst_buffer_unmap (buf, &map); 9486 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode]; 9487 9488 bad_data: 9489 gst_buffer_unmap (buf, &map); 9490 return 0; 9491 } 9492 9493 static gboolean 9494 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux, 9495 GstByteReader * reader, guint32 * matrix, const gchar * atom) 9496 { 9497 /* 9498 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30) 9499 * [0 1 2] 9500 * [3 4 5] 9501 * [6 7 8] 9502 */ 9503 9504 if (gst_byte_reader_get_remaining (reader) < 36) 9505 return FALSE; 9506 9507 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader); 9508 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader); 9509 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader); 9510 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader); 9511 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader); 9512 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader); 9513 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader); 9514 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader); 9515 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader); 9516 9517 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom); 9518 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16, 9519 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16, 9520 matrix[2] & 0xFF); 9521 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16, 9522 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16, 9523 matrix[5] & 0xFF); 9524 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16, 9525 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16, 9526 matrix[8] & 0xFF); 9527 9528 return TRUE; 9529 } 9530 9531 static void 9532 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux, 9533 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist) 9534 { 9535 9536 /* [a b c] 9537 * [d e f] 9538 * [g h i] 9539 * 9540 * This macro will only compare value abdegh, it expects cfi to have already 9541 * been checked 9542 */ 9543 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \ 9544 (m)[3] == (d << 16) && (m)[4] == (e << 16)) 9545 9546 /* only handle the cases where the last column has standard values */ 9547 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) { 9548 const gchar *rotation_tag = NULL; 9549 9550 /* no rotation needed */ 9551 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) { 9552 /* NOP */ 9553 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) { 9554 rotation_tag = "rotate-90"; 9555 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) { 9556 rotation_tag = "rotate-180"; 9557 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) { 9558 rotation_tag = "rotate-270"; 9559 } else { 9560 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values"); 9561 } 9562 9563 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s", 9564 rotation_tag); 9565 if (rotation_tag != NULL) { 9566 if (*taglist == NULL) 9567 *taglist = gst_tag_list_new_empty (); 9568 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE, 9569 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL); 9570 } 9571 } else { 9572 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values"); 9573 } 9574 } 9575 9576 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for 9577 * protected streams (sinf, frma, schm and schi); if the protection scheme is 9578 * Common Encryption (cenc), the function will also parse the tenc box (defined 9579 * in ISO/IEC 23001-7). @container points to the node that contains these boxes 9580 * (typically an enc[v|a|t|s] sample entry); the function will set 9581 * @original_fmt to the fourcc of the original unencrypted stream format. 9582 * Returns TRUE if successful; FALSE otherwise. */ 9583 static gboolean 9584 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux, 9585 QtDemuxStream * stream, GNode * container, guint32 * original_fmt) 9586 { 9587 GNode *sinf; 9588 GNode *frma; 9589 GNode *schm; 9590 GNode *schi; 9591 9592 g_return_val_if_fail (qtdemux != NULL, FALSE); 9593 g_return_val_if_fail (stream != NULL, FALSE); 9594 g_return_val_if_fail (container != NULL, FALSE); 9595 g_return_val_if_fail (original_fmt != NULL, FALSE); 9596 9597 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf); 9598 if (G_UNLIKELY (!sinf)) { 9599 if (stream->protection_scheme_type == FOURCC_cenc) { 9600 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is " 9601 "mandatory for Common Encryption"); 9602 return FALSE; 9603 } 9604 return TRUE; 9605 } 9606 9607 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma); 9608 if (G_UNLIKELY (!frma)) { 9609 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box"); 9610 return FALSE; 9611 } 9612 9613 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8); 9614 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'", 9615 GST_FOURCC_ARGS (*original_fmt)); 9616 9617 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm); 9618 if (!schm) { 9619 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box"); 9620 return FALSE; 9621 } 9622 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12); 9623 stream->protection_scheme_version = 9624 QT_UINT32 ((const guint8 *) schm->data + 16); 9625 9626 GST_DEBUG_OBJECT (qtdemux, 9627 "protection_scheme_type: %" GST_FOURCC_FORMAT ", " 9628 "protection_scheme_version: %#010x", 9629 GST_FOURCC_ARGS (stream->protection_scheme_type), 9630 stream->protection_scheme_version); 9631 9632 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi); 9633 if (!schi) { 9634 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box"); 9635 return FALSE; 9636 } 9637 if (stream->protection_scheme_type == FOURCC_cenc) { 9638 QtDemuxCencSampleSetInfo *info; 9639 GNode *tenc; 9640 const guint8 *tenc_data; 9641 guint32 isEncrypted; 9642 guint8 iv_size; 9643 const guint8 *default_kid; 9644 GstBuffer *kid_buf; 9645 9646 if (G_UNLIKELY (!stream->protection_scheme_info)) 9647 stream->protection_scheme_info = 9648 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo)); 9649 9650 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info; 9651 9652 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc); 9653 if (!tenc) { 9654 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, " 9655 "which is mandatory for Common Encryption"); 9656 return FALSE; 9657 } 9658 tenc_data = (const guint8 *) tenc->data + 12; 9659 isEncrypted = QT_UINT24 (tenc_data); 9660 iv_size = QT_UINT8 (tenc_data + 3); 9661 default_kid = (tenc_data + 4); 9662 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL); 9663 gst_buffer_fill (kid_buf, 0, default_kid, 16); 9664 if (info->default_properties) 9665 gst_structure_free (info->default_properties); 9666 info->default_properties = 9667 gst_structure_new ("application/x-cenc", 9668 "iv_size", G_TYPE_UINT, iv_size, 9669 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1), 9670 "kid", GST_TYPE_BUFFER, kid_buf, NULL); 9671 GST_DEBUG_OBJECT (qtdemux, "default sample properties: " 9672 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size); 9673 gst_buffer_unref (kid_buf); 9674 } 9675 return TRUE; 9676 } 9677 9678 /* parse the traks. 9679 * With each track we associate a new QtDemuxStream that contains all the info 9680 * about the trak. 9681 * traks that do not decode to something (like strm traks) will not have a pad. 9682 */ 9683 static gboolean 9684 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) 9685 { 9686 GstByteReader tkhd; 9687 int offset; 9688 GNode *mdia; 9689 GNode *mdhd; 9690 GNode *hdlr; 9691 GNode *minf; 9692 GNode *stbl; 9693 GNode *stsd; 9694 GNode *mp4a; 9695 GNode *mp4v; 9696 GNode *esds; 9697 GNode *tref; 9698 GNode *udta; 9699 GNode *svmi; 9700 9701 QtDemuxStream *stream = NULL; 9702 gboolean new_stream = FALSE; 9703 const guint8 *stsd_data; 9704 const guint8 *stsd_entry_data; 9705 guint remaining_stsd_len; 9706 guint stsd_entry_count; 9707 guint stsd_index; 9708 guint16 lang_code; /* quicktime lang code or packed iso code */ 9709 guint32 version; 9710 guint32 tkhd_flags = 0; 9711 guint8 tkhd_version = 0; 9712 guint32 w = 0, h = 0; 9713 guint value_size, stsd_len, len; 9714 guint32 track_id; 9715 guint32 dummy; 9716 9717 GST_DEBUG_OBJECT (qtdemux, "parse_trak"); 9718 9719 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd) 9720 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version) 9721 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags)) 9722 goto corrupt_file; 9723 9724 /* pick between 64 or 32 bits */ 9725 value_size = tkhd_version == 1 ? 8 : 4; 9726 if (!gst_byte_reader_skip (&tkhd, value_size * 2) || 9727 !gst_byte_reader_get_uint32_be (&tkhd, &track_id)) 9728 goto corrupt_file; 9729 9730 if (!qtdemux->got_moov) { 9731 if (qtdemux_find_stream (qtdemux, track_id)) 9732 goto existing_stream; 9733 stream = _create_stream (); 9734 stream->track_id = track_id; 9735 new_stream = TRUE; 9736 } else { 9737 stream = qtdemux_find_stream (qtdemux, track_id); 9738 if (!stream) { 9739 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it"); 9740 goto skip_track; 9741 } 9742 9743 /* reset reused stream */ 9744 gst_qtdemux_stream_reset (qtdemux, stream); 9745 } 9746 /* need defaults for fragments */ 9747 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy); 9748 9749 if ((tkhd_flags & 1) == 0) 9750 stream->disabled = TRUE; 9751 9752 #ifdef GSTREAMER_LITE 9753 // set track_enabled based on bit 0 of flags 9754 stream->track_enabled = (gboolean)(tkhd_flags & 0x000001); 9755 #endif // GSTREAMER_LITE 9756 9757 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u", 9758 tkhd_version, tkhd_flags, stream->track_id); 9759 9760 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia))) 9761 goto corrupt_file; 9762 9763 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) { 9764 /* be nice for some crooked mjp2 files that use mhdr for mdhd */ 9765 if (qtdemux->major_brand != FOURCC_mjp2 || 9766 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr))) 9767 goto corrupt_file; 9768 } 9769 9770 len = QT_UINT32 ((guint8 *) mdhd->data); 9771 version = QT_UINT32 ((guint8 *) mdhd->data + 8); 9772 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version); 9773 if (version == 0x01000000) { 9774 if (len < 38) 9775 goto corrupt_file; 9776 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28); 9777 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32); 9778 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36); 9779 } else { 9780 if (len < 30) 9781 goto corrupt_file; 9782 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20); 9783 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24); 9784 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28); 9785 } 9786 9787 if (lang_code < 0x400) { 9788 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code); 9789 } else if (lang_code == 0x7fff) { 9790 stream->lang_id[0] = 0; /* unspecified */ 9791 } else { 9792 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F); 9793 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F); 9794 stream->lang_id[2] = 0x60 + (lang_code & 0x1F); 9795 stream->lang_id[3] = 0; 9796 } 9797 9798 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT, 9799 stream->timescale); 9800 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT, 9801 stream->duration); 9802 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s", 9803 lang_code, stream->lang_id); 9804 9805 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0)) 9806 goto corrupt_file; 9807 9808 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) { 9809 /* chapters track reference */ 9810 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap); 9811 if (chap) { 9812 gsize length = GST_READ_UINT32_BE (chap->data); 9813 if (qtdemux->chapters_track_id) 9814 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks"); 9815 9816 if (length >= 12) { 9817 qtdemux->chapters_track_id = 9818 GST_READ_UINT32_BE ((gint8 *) chap->data + 8); 9819 } 9820 } 9821 } 9822 9823 /* fragmented files may have bogus duration in moov */ 9824 if (!qtdemux->fragmented && 9825 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) { 9826 guint64 tdur1, tdur2; 9827 9828 /* don't overflow */ 9829 tdur1 = stream->timescale * (guint64) qtdemux->duration; 9830 tdur2 = qtdemux->timescale * (guint64) stream->duration; 9831 9832 /* HACK: 9833 * some of those trailers, nowadays, have prologue images that are 9834 * themselves video tracks as well. I haven't really found a way to 9835 * identify those yet, except for just looking at their duration. */ 9836 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) { 9837 GST_WARNING_OBJECT (qtdemux, 9838 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT 9839 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream " 9840 "found, assuming preview image or something; skipping track", 9841 stream->duration, stream->timescale, qtdemux->duration, 9842 qtdemux->timescale); 9843 if (new_stream) 9844 gst_qtdemux_stream_free (qtdemux, stream); 9845 return TRUE; 9846 } 9847 } 9848 9849 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr))) 9850 goto corrupt_file; 9851 9852 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT, 9853 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12))); 9854 9855 len = QT_UINT32 ((guint8 *) hdlr->data); 9856 if (len >= 20) 9857 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16); 9858 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT, 9859 GST_FOURCC_ARGS (stream->subtype)); 9860 9861 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf))) 9862 goto corrupt_file; 9863 9864 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl))) 9865 goto corrupt_file; 9866 9867 /*parse svmi header if existing */ 9868 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi); 9869 if (svmi) { 9870 len = QT_UINT32 ((guint8 *) svmi->data); 9871 version = QT_UINT32 ((guint8 *) svmi->data + 8); 9872 if (!version) { 9873 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE; 9874 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE; 9875 guint8 frame_type, frame_layout; 9876 9877 /* MPEG-A stereo video */ 9878 if (qtdemux->major_brand == FOURCC_ss02) 9879 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO; 9880 9881 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12); 9882 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01; 9883 switch (frame_type) { 9884 case 0: 9885 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE; 9886 break; 9887 case 1: 9888 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED; 9889 break; 9890 case 2: 9891 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME; 9892 break; 9893 case 3: 9894 /* mode 3 is primary/secondary view sequence, ie 9895 * left/right views in separate tracks. See section 7.2 9896 * of ISO/IEC 23000-11:2009 */ 9897 GST_FIXME_OBJECT (qtdemux, 9898 "Implement stereo video in separate streams"); 9899 } 9900 9901 if ((frame_layout & 0x1) == 0) 9902 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST; 9903 9904 GST_LOG_OBJECT (qtdemux, 9905 "StereoVideo: composition type: %u, is_left_first: %u", 9906 frame_type, frame_layout); 9907 stream->multiview_mode = mode; 9908 stream->multiview_flags = flags; 9909 } 9910 } 9911 9912 /* parse rest of tkhd */ 9913 if (stream->subtype == FOURCC_vide) { 9914 guint32 matrix[9]; 9915 9916 /* version 1 uses some 64-bit ints */ 9917 if (!gst_byte_reader_skip (&tkhd, 20 + value_size)) 9918 goto corrupt_file; 9919 9920 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd")) 9921 goto corrupt_file; 9922 9923 if (!gst_byte_reader_get_uint32_be (&tkhd, &w) 9924 || !gst_byte_reader_get_uint32_be (&tkhd, &h)) 9925 goto corrupt_file; 9926 9927 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix, 9928 &stream->stream_tags); 9929 } 9930 9931 /* parse stsd */ 9932 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd))) 9933 goto corrupt_file; 9934 stsd_data = (const guint8 *) stsd->data; 9935 9936 /* stsd should at least have one entry */ 9937 stsd_len = QT_UINT32 (stsd_data); 9938 if (stsd_len < 24) { 9939 /* .. but skip stream with empty stsd produced by some Vivotek cameras */ 9940 if (stream->subtype == FOURCC_vivo) { 9941 if (new_stream) 9942 gst_qtdemux_stream_free (qtdemux, stream); 9943 return TRUE; 9944 } else { 9945 goto corrupt_file; 9946 } 9947 } 9948 9949 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12); 9950 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count); 9951 #ifdef GSTREAMER_LITE 9952 // Even if we check stsd header length (stsd_len) to make sure we have at least 9953 // one entry, we still might have actual entry count set to 0. g_new0() will 9954 // return NULL if fail or count is 0. 9955 if (stream->stsd_entries == NULL) { 9956 goto corrupt_file; 9957 } 9958 #endif // GSTREAMER_LITE 9959 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len); 9960 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count); 9961 9962 stsd_entry_data = stsd_data + 16; 9963 remaining_stsd_len = stsd_len - 16; 9964 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) { 9965 guint32 fourcc; 9966 gchar *codec = NULL; 9967 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index]; 9968 9969 /* and that entry should fit within stsd */ 9970 len = QT_UINT32 (stsd_entry_data); 9971 if (len > remaining_stsd_len) 9972 goto corrupt_file; 9973 9974 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4); 9975 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT, 9976 GST_FOURCC_ARGS (entry->fourcc)); 9977 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len); 9978 9979 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi)) 9980 goto error_encrypted; 9981 9982 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) { 9983 /* FIXME this looks wrong, there might be multiple children 9984 * with the same type */ 9985 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc); 9986 stream->protected = TRUE; 9987 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc)) 9988 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info"); 9989 } 9990 9991 if (stream->subtype == FOURCC_vide) { 9992 GNode *colr; 9993 GNode *fiel; 9994 GNode *pasp; 9995 gboolean gray; 9996 gint depth, palette_size, palette_count; 9997 guint32 *palette_data = NULL; 9998 9999 entry->sampled = TRUE; 10000 10001 stream->display_width = w >> 16; 10002 stream->display_height = h >> 16; 10003 10004 offset = 16; 10005 if (len < 86) /* TODO verify */ 10006 goto corrupt_file; 10007 10008 entry->width = QT_UINT16 (stsd_entry_data + offset + 16); 10009 entry->height = QT_UINT16 (stsd_entry_data + offset + 18); 10010 entry->fps_n = 0; /* this is filled in later */ 10011 entry->fps_d = 0; /* this is filled in later */ 10012 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66); 10013 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68); 10014 10015 /* if color_table_id is 0, ctab atom must follow; however some files 10016 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so 10017 * if color table is not present we'll correct the value */ 10018 if (entry->color_table_id == 0 && 10019 (len < 90 10020 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) { 10021 entry->color_table_id = -1; 10022 } 10023 10024 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d", 10025 entry->width, entry->height, entry->bits_per_sample, 10026 entry->color_table_id); 10027 10028 depth = entry->bits_per_sample; 10029 10030 /* more than 32 bits means grayscale */ 10031 gray = (depth > 32); 10032 /* low 32 bits specify the depth */ 10033 depth &= 0x1F; 10034 10035 /* different number of palette entries is determined by depth. */ 10036 palette_count = 0; 10037 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8)) 10038 palette_count = (1 << depth); 10039 palette_size = palette_count * 4; 10040 10041 if (entry->color_table_id) { 10042 switch (palette_count) { 10043 case 0: 10044 break; 10045 case 2: 10046 palette_data = g_memdup (ff_qt_default_palette_2, palette_size); 10047 break; 10048 case 4: 10049 palette_data = g_memdup (ff_qt_default_palette_4, palette_size); 10050 break; 10051 case 16: 10052 if (gray) 10053 palette_data = 10054 g_memdup (ff_qt_grayscale_palette_16, palette_size); 10055 else 10056 palette_data = g_memdup (ff_qt_default_palette_16, palette_size); 10057 break; 10058 case 256: 10059 if (gray) 10060 palette_data = 10061 g_memdup (ff_qt_grayscale_palette_256, palette_size); 10062 else 10063 palette_data = g_memdup (ff_qt_default_palette_256, palette_size); 10064 break; 10065 default: 10066 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX, 10067 (_("The video in this file might not play correctly.")), 10068 ("unsupported palette depth %d", depth)); 10069 break; 10070 } 10071 } else { 10072 gint i, j, start, end; 10073 10074 if (len < 94) 10075 goto corrupt_file; 10076 10077 /* read table */ 10078 start = QT_UINT32 (stsd_entry_data + offset + 70); 10079 palette_count = QT_UINT16 (stsd_entry_data + offset + 74); 10080 end = QT_UINT16 (stsd_entry_data + offset + 76); 10081 10082 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d", 10083 start, end, palette_count); 10084 10085 if (end > 255) 10086 end = 255; 10087 if (start > end) 10088 start = end; 10089 10090 if (len < 94 + (end - start) * 8) 10091 goto corrupt_file; 10092 10093 /* palette is always the same size */ 10094 palette_data = g_malloc0 (256 * 4); 10095 palette_size = 256 * 4; 10096 10097 for (j = 0, i = start; i <= end; j++, i++) { 10098 guint32 a, r, g, b; 10099 10100 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8)); 10101 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8)); 10102 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8)); 10103 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8)); 10104 10105 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) | 10106 (g & 0xff00) | (b >> 8); 10107 } 10108 } 10109 10110 if (entry->caps) 10111 gst_caps_unref (entry->caps); 10112 10113 entry->caps = 10114 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data, 10115 &codec); 10116 if (G_UNLIKELY (!entry->caps)) { 10117 g_free (palette_data); 10118 goto unknown_stream; 10119 } 10120 10121 if (codec) { 10122 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE, 10123 GST_TAG_VIDEO_CODEC, codec, NULL); 10124 g_free (codec); 10125 codec = NULL; 10126 } 10127 10128 if (palette_data) { 10129 GstStructure *s; 10130 10131 if (entry->rgb8_palette) 10132 gst_memory_unref (entry->rgb8_palette); 10133 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, 10134 palette_data, palette_size, 0, palette_size, palette_data, g_free); 10135 10136 s = gst_caps_get_structure (entry->caps, 0); 10137 10138 /* non-raw video has a palette_data property. raw video has the palette as 10139 * an extra plane that we append to the output buffers before we push 10140 * them*/ 10141 if (!gst_structure_has_name (s, "video/x-raw")) { 10142 GstBuffer *palette; 10143 10144 palette = gst_buffer_new (); 10145 gst_buffer_append_memory (palette, entry->rgb8_palette); 10146 entry->rgb8_palette = NULL; 10147 10148 gst_caps_set_simple (entry->caps, "palette_data", 10149 GST_TYPE_BUFFER, palette, NULL); 10150 gst_buffer_unref (palette); 10151 } 10152 } else if (palette_count != 0) { 10153 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED, 10154 (NULL), ("Unsupported palette depth %d", depth)); 10155 } 10156 10157 GST_LOG_OBJECT (qtdemux, "frame count: %u", 10158 QT_UINT16 (stsd_entry_data + offset + 32)); 10159 10160 esds = NULL; 10161 pasp = NULL; 10162 colr = NULL; 10163 fiel = NULL; 10164 /* pick 'the' stsd child */ 10165 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index); 10166 if (!stream->protected) { 10167 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) { 10168 mp4v = NULL; 10169 } 10170 } else { 10171 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) { 10172 mp4v = NULL; 10173 } 10174 } 10175 10176 if (mp4v) { 10177 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds); 10178 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp); 10179 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr); 10180 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel); 10181 } 10182 10183 if (pasp) { 10184 const guint8 *pasp_data = (const guint8 *) pasp->data; 10185 gint len = QT_UINT32 (pasp_data); 10186 10187 if (len == 16) { 10188 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8); 10189 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12); 10190 } else { 10191 CUR_STREAM (stream)->par_w = 0; 10192 CUR_STREAM (stream)->par_h = 0; 10193 } 10194 } else { 10195 CUR_STREAM (stream)->par_w = 0; 10196 CUR_STREAM (stream)->par_h = 0; 10197 } 10198 10199 if (fiel) { 10200 const guint8 *fiel_data = (const guint8 *) fiel->data; 10201 gint len = QT_UINT32 (fiel_data); 10202 10203 if (len == 10) { 10204 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8); 10205 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9); 10206 } 10207 } 10208 10209 if (colr) { 10210 const guint8 *colr_data = (const guint8 *) colr->data; 10211 gint len = QT_UINT32 (colr_data); 10212 10213 if (len == 19 || len == 18) { 10214 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8); 10215 10216 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) { 10217 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12); 10218 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14); 10219 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16); 10220 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE; 10221 10222 switch (primaries) { 10223 case 1: 10224 CUR_STREAM (stream)->colorimetry.primaries = 10225 GST_VIDEO_COLOR_PRIMARIES_BT709; 10226 break; 10227 case 5: 10228 CUR_STREAM (stream)->colorimetry.primaries = 10229 GST_VIDEO_COLOR_PRIMARIES_BT470BG; 10230 break; 10231 case 6: 10232 CUR_STREAM (stream)->colorimetry.primaries = 10233 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M; 10234 break; 10235 case 9: 10236 CUR_STREAM (stream)->colorimetry.primaries = 10237 GST_VIDEO_COLOR_PRIMARIES_BT2020; 10238 break; 10239 default: 10240 break; 10241 } 10242 10243 switch (transfer_function) { 10244 case 1: 10245 CUR_STREAM (stream)->colorimetry.transfer = 10246 GST_VIDEO_TRANSFER_BT709; 10247 break; 10248 case 7: 10249 CUR_STREAM (stream)->colorimetry.transfer = 10250 GST_VIDEO_TRANSFER_SMPTE240M; 10251 break; 10252 default: 10253 break; 10254 } 10255 10256 switch (matrix) { 10257 case 1: 10258 CUR_STREAM (stream)->colorimetry.matrix = 10259 GST_VIDEO_COLOR_MATRIX_BT709; 10260 break; 10261 case 6: 10262 CUR_STREAM (stream)->colorimetry.matrix = 10263 GST_VIDEO_COLOR_MATRIX_BT601; 10264 break; 10265 case 7: 10266 CUR_STREAM (stream)->colorimetry.matrix = 10267 GST_VIDEO_COLOR_MATRIX_SMPTE240M; 10268 break; 10269 case 9: 10270 CUR_STREAM (stream)->colorimetry.matrix = 10271 GST_VIDEO_COLOR_MATRIX_BT2020; 10272 break; 10273 default: 10274 break; 10275 } 10276 10277 CUR_STREAM (stream)->colorimetry.range = 10278 full_range ? GST_VIDEO_COLOR_RANGE_0_255 : 10279 GST_VIDEO_COLOR_RANGE_16_235; 10280 } else { 10281 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type"); 10282 } 10283 } else { 10284 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size"); 10285 } 10286 } 10287 10288 if (esds) { 10289 #ifdef GSTREAMER_LITE 10290 if (!gst_qtdemux_handle_esds (qtdemux, stream, entry, esds, 10291 stream->stream_tags)) 10292 goto corrupt_file; 10293 #else 10294 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds, 10295 stream->stream_tags); 10296 #endif // GSTREAMER_LITE 10297 } else { 10298 switch (fourcc) { 10299 case FOURCC_H264: 10300 case FOURCC_avc1: 10301 case FOURCC_avc3: 10302 { 10303 gint len = QT_UINT32 (stsd_entry_data) - 0x56; 10304 const guint8 *avc_data = stsd_entry_data + 0x56; 10305 10306 /* find avcC */ 10307 while (len >= 0x8) { 10308 gint size; 10309 10310 if (QT_UINT32 (avc_data) <= len) 10311 size = QT_UINT32 (avc_data) - 0x8; 10312 else 10313 size = len - 0x8; 10314 10315 if (size < 1) 10316 /* No real data, so break out */ 10317 break; 10318 10319 switch (QT_FOURCC (avc_data + 0x4)) { 10320 case FOURCC_avcC: 10321 { 10322 /* parse, if found */ 10323 GstBuffer *buf; 10324 10325 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd"); 10326 10327 /* First 4 bytes are the length of the atom, the next 4 bytes 10328 * are the fourcc, the next 1 byte is the version, and the 10329 * subsequent bytes are profile_tier_level structure like data. */ 10330 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps, 10331 avc_data + 8 + 1, size - 1); 10332 buf = gst_buffer_new_and_alloc (size); 10333 gst_buffer_fill (buf, 0, avc_data + 0x8, size); 10334 gst_caps_set_simple (entry->caps, 10335 "codec_data", GST_TYPE_BUFFER, buf, NULL); 10336 gst_buffer_unref (buf); 10337 10338 break; 10339 } 10340 case FOURCC_strf: 10341 { 10342 GstBuffer *buf; 10343 10344 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd"); 10345 10346 /* First 4 bytes are the length of the atom, the next 4 bytes 10347 * are the fourcc, next 40 bytes are BITMAPINFOHEADER, 10348 * next 1 byte is the version, and the 10349 * subsequent bytes are sequence parameter set like data. */ 10350 10351 size -= 40; /* we'll be skipping BITMAPINFOHEADER */ 10352 if (size > 1) { 10353 gst_codec_utils_h264_caps_set_level_and_profile 10354 (entry->caps, avc_data + 8 + 40 + 1, size - 1); 10355 10356 buf = gst_buffer_new_and_alloc (size); 10357 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size); 10358 gst_caps_set_simple (entry->caps, 10359 "codec_data", GST_TYPE_BUFFER, buf, NULL); 10360 gst_buffer_unref (buf); 10361 } 10362 break; 10363 } 10364 case FOURCC_btrt: 10365 { 10366 guint avg_bitrate, max_bitrate; 10367 10368 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */ 10369 if (size < 12) 10370 break; 10371 10372 max_bitrate = QT_UINT32 (avc_data + 0xc); 10373 avg_bitrate = QT_UINT32 (avc_data + 0x10); 10374 10375 if (!max_bitrate && !avg_bitrate) 10376 break; 10377 10378 /* Some muxers seem to swap the average and maximum bitrates 10379 * (I'm looking at you, YouTube), so we swap for sanity. */ 10380 if (max_bitrate > 0 && max_bitrate < avg_bitrate) { 10381 guint temp = avg_bitrate; 10382 10383 avg_bitrate = max_bitrate; 10384 max_bitrate = temp; 10385 } 10386 10387 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) { 10388 gst_tag_list_add (stream->stream_tags, 10389 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE, 10390 max_bitrate, NULL); 10391 } 10392 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) { 10393 gst_tag_list_add (stream->stream_tags, 10394 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate, 10395 NULL); 10396 } 10397 10398 break; 10399 } 10400 10401 default: 10402 break; 10403 } 10404 10405 len -= size + 8; 10406 avc_data += size + 8; 10407 } 10408 10409 break; 10410 } 10411 case FOURCC_H265: 10412 case FOURCC_hvc1: 10413 case FOURCC_hev1: 10414 { 10415 gint len = QT_UINT32 (stsd_entry_data) - 0x56; 10416 const guint8 *hevc_data = stsd_entry_data + 0x56; 10417 10418 /* find hevc */ 10419 while (len >= 0x8) { 10420 gint size; 10421 10422 if (QT_UINT32 (hevc_data) <= len) 10423 size = QT_UINT32 (hevc_data) - 0x8; 10424 else 10425 size = len - 0x8; 10426 10427 if (size < 1) 10428 /* No real data, so break out */ 10429 break; 10430 10431 switch (QT_FOURCC (hevc_data + 0x4)) { 10432 case FOURCC_hvcC: 10433 { 10434 /* parse, if found */ 10435 GstBuffer *buf; 10436 10437 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd"); 10438 10439 /* First 4 bytes are the length of the atom, the next 4 bytes 10440 * are the fourcc, the next 1 byte is the version, and the 10441 * subsequent bytes are sequence parameter set like data. */ 10442 gst_codec_utils_h265_caps_set_level_tier_and_profile 10443 (entry->caps, hevc_data + 8 + 1, size - 1); 10444 10445 buf = gst_buffer_new_and_alloc (size); 10446 gst_buffer_fill (buf, 0, hevc_data + 0x8, size); 10447 gst_caps_set_simple (entry->caps, 10448 "codec_data", GST_TYPE_BUFFER, buf, NULL); 10449 gst_buffer_unref (buf); 10450 break; 10451 } 10452 default: 10453 break; 10454 } 10455 len -= size + 8; 10456 hevc_data += size + 8; 10457 } 10458 break; 10459 } 10460 case FOURCC_mp4v: 10461 case FOURCC_MP4V: 10462 case FOURCC_fmp4: 10463 case FOURCC_FMP4: 10464 case FOURCC_xvid: 10465 case FOURCC_XVID: 10466 { 10467 GNode *glbl; 10468 10469 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT, 10470 GST_FOURCC_ARGS (fourcc)); 10471 10472 /* codec data might be in glbl extension atom */ 10473 glbl = mp4v ? 10474 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL; 10475 if (glbl) { 10476 guint8 *data; 10477 GstBuffer *buf; 10478 gint len; 10479 10480 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd"); 10481 data = glbl->data; 10482 len = QT_UINT32 (data); 10483 if (len > 0x8) { 10484 len -= 0x8; 10485 buf = gst_buffer_new_and_alloc (len); 10486 gst_buffer_fill (buf, 0, data + 8, len); 10487 gst_caps_set_simple (entry->caps, 10488 "codec_data", GST_TYPE_BUFFER, buf, NULL); 10489 gst_buffer_unref (buf); 10490 } 10491 } 10492 break; 10493 } 10494 case FOURCC_mjp2: 10495 { 10496 /* see annex I of the jpeg2000 spec */ 10497 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef; 10498 const guint8 *data; 10499 const gchar *colorspace = NULL; 10500 gint ncomp = 0; 10501 guint32 ncomp_map = 0; 10502 gint32 *comp_map = NULL; 10503 guint32 nchan_def = 0; 10504 gint32 *chan_def = NULL; 10505 10506 GST_DEBUG_OBJECT (qtdemux, "found mjp2"); 10507 /* some required atoms */ 10508 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index); 10509 if (!mjp2) 10510 break; 10511 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h); 10512 if (!jp2h) 10513 break; 10514 10515 /* number of components; redundant with info in codestream, but useful 10516 to a muxer */ 10517 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr); 10518 if (!ihdr || QT_UINT32 (ihdr->data) != 22) 10519 break; 10520 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16); 10521 10522 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr); 10523 if (!colr) 10524 break; 10525 GST_DEBUG_OBJECT (qtdemux, "found colr"); 10526 /* extract colour space info */ 10527 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) { 10528 switch (QT_UINT32 ((guint8 *) colr->data + 11)) { 10529 case 16: 10530 colorspace = "sRGB"; 10531 break; 10532 case 17: 10533 colorspace = "GRAY"; 10534 break; 10535 case 18: 10536 colorspace = "sYUV"; 10537 break; 10538 default: 10539 colorspace = NULL; 10540 break; 10541 } 10542 } 10543 if (!colorspace) 10544 /* colr is required, and only values 16, 17, and 18 are specified, 10545 so error if we have no colorspace */ 10546 break; 10547 10548 /* extract component mapping */ 10549 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap); 10550 if (cmap) { 10551 guint32 cmap_len = 0; 10552 int i; 10553 cmap_len = QT_UINT32 (cmap->data); 10554 if (cmap_len >= 8) { 10555 /* normal box, subtract off header */ 10556 cmap_len -= 8; 10557 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */ 10558 if (cmap_len % 4 == 0) { 10559 ncomp_map = (cmap_len / 4); 10560 comp_map = g_new0 (gint32, ncomp_map); 10561 for (i = 0; i < ncomp_map; i++) { 10562 guint16 cmp; 10563 guint8 mtyp, pcol; 10564 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4); 10565 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2); 10566 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3); 10567 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp; 10568 } 10569 } 10570 } 10571 } 10572 /* extract channel definitions */ 10573 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef); 10574 if (cdef) { 10575 guint32 cdef_len = 0; 10576 int i; 10577 cdef_len = QT_UINT32 (cdef->data); 10578 if (cdef_len >= 10) { 10579 /* normal box, subtract off header and len */ 10580 cdef_len -= 10; 10581 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */ 10582 if (cdef_len % 6 == 0) { 10583 nchan_def = (cdef_len / 6); 10584 chan_def = g_new0 (gint32, nchan_def); 10585 for (i = 0; i < nchan_def; i++) 10586 chan_def[i] = -1; 10587 for (i = 0; i < nchan_def; i++) { 10588 guint16 cn, typ, asoc; 10589 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6); 10590 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2); 10591 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4); 10592 if (cn < nchan_def) { 10593 switch (typ) { 10594 case 0: 10595 chan_def[cn] = asoc; 10596 break; 10597 case 1: 10598 chan_def[cn] = 0; /* alpha */ 10599 break; 10600 default: 10601 chan_def[cn] = -typ; 10602 } 10603 } 10604 } 10605 } 10606 } 10607 } 10608 10609 gst_caps_set_simple (entry->caps, 10610 "num-components", G_TYPE_INT, ncomp, NULL); 10611 gst_caps_set_simple (entry->caps, 10612 "colorspace", G_TYPE_STRING, colorspace, NULL); 10613 10614 if (comp_map) { 10615 GValue arr = { 0, }; 10616 GValue elt = { 0, }; 10617 int i; 10618 g_value_init (&arr, GST_TYPE_ARRAY); 10619 g_value_init (&elt, G_TYPE_INT); 10620 for (i = 0; i < ncomp_map; i++) { 10621 g_value_set_int (&elt, comp_map[i]); 10622 gst_value_array_append_value (&arr, &elt); 10623 } 10624 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0), 10625 "component-map", &arr); 10626 g_value_unset (&elt); 10627 g_value_unset (&arr); 10628 g_free (comp_map); 10629 } 10630 10631 if (chan_def) { 10632 GValue arr = { 0, }; 10633 GValue elt = { 0, }; 10634 int i; 10635 g_value_init (&arr, GST_TYPE_ARRAY); 10636 g_value_init (&elt, G_TYPE_INT); 10637 for (i = 0; i < nchan_def; i++) { 10638 g_value_set_int (&elt, chan_def[i]); 10639 gst_value_array_append_value (&arr, &elt); 10640 } 10641 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0), 10642 "channel-definitions", &arr); 10643 g_value_unset (&elt); 10644 g_value_unset (&arr); 10645 g_free (chan_def); 10646 } 10647 10648 /* some optional atoms */ 10649 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel); 10650 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x); 10651 10652 /* indicate possible fields in caps */ 10653 if (field) { 10654 data = (guint8 *) field->data + 8; 10655 if (*data != 1) 10656 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT, 10657 (gint) * data, NULL); 10658 } 10659 /* add codec_data if provided */ 10660 if (prefix) { 10661 GstBuffer *buf; 10662 gint len; 10663 10664 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd"); 10665 data = prefix->data; 10666 len = QT_UINT32 (data); 10667 if (len > 0x8) { 10668 len -= 0x8; 10669 buf = gst_buffer_new_and_alloc (len); 10670 gst_buffer_fill (buf, 0, data + 8, len); 10671 gst_caps_set_simple (entry->caps, 10672 "codec_data", GST_TYPE_BUFFER, buf, NULL); 10673 gst_buffer_unref (buf); 10674 } 10675 } 10676 break; 10677 } 10678 case FOURCC_SVQ3: 10679 case FOURCC_VP31: 10680 { 10681 GstBuffer *buf; 10682 GstBuffer *seqh = NULL; 10683 const guint8 *gamma_data = NULL; 10684 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */ 10685 10686 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data, 10687 &seqh); 10688 if (gamma_data) { 10689 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE, 10690 QT_FP32 (gamma_data), NULL); 10691 } 10692 if (seqh) { 10693 /* sorry for the bad name, but we don't know what this is, other 10694 * than its own fourcc */ 10695 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh, 10696 NULL); 10697 gst_buffer_unref (seqh); 10698 } 10699 10700 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd"); 10701 buf = gst_buffer_new_and_alloc (len); 10702 gst_buffer_fill (buf, 0, stsd_data, len); 10703 gst_caps_set_simple (entry->caps, 10704 "codec_data", GST_TYPE_BUFFER, buf, NULL); 10705 gst_buffer_unref (buf); 10706 break; 10707 } 10708 case FOURCC_jpeg: 10709 { 10710 /* https://developer.apple.com/standards/qtff-2001.pdf, 10711 * page 92, "Video Sample Description", under table 3.1 */ 10712 GstByteReader br; 10713 10714 const gint compressor_offset = 10715 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2; 10716 const gint min_size = compressor_offset + 32 + 2 + 2; 10717 GNode *jpeg; 10718 guint32 len; 10719 guint16 color_table_id = 0; 10720 gboolean ok; 10721 10722 GST_DEBUG_OBJECT (qtdemux, "found jpeg"); 10723 10724 /* recover information on interlaced/progressive */ 10725 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg); 10726 if (!jpeg) 10727 break; 10728 10729 len = QT_UINT32 (jpeg->data); 10730 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len, 10731 min_size); 10732 if (len >= min_size) { 10733 gst_byte_reader_init (&br, jpeg->data, len); 10734 10735 gst_byte_reader_skip (&br, compressor_offset + 32 + 2); 10736 gst_byte_reader_get_uint16_le (&br, &color_table_id); 10737 if (color_table_id != 0) { 10738 /* the spec says there can be concatenated chunks in the data, and we want 10739 * to find one called field. Walk through them. */ 10740 gint offset = min_size; 10741 while (offset + 8 < len) { 10742 guint32 size = 0, tag; 10743 ok = gst_byte_reader_get_uint32_le (&br, &size); 10744 ok &= gst_byte_reader_get_uint32_le (&br, &tag); 10745 if (!ok || size < 8) { 10746 GST_WARNING_OBJECT (qtdemux, 10747 "Failed to walk optional chunk list"); 10748 break; 10749 } 10750 GST_DEBUG_OBJECT (qtdemux, 10751 "Found optional %4.4s chunk, size %u", 10752 (const char *) &tag, size); 10753 if (tag == FOURCC_fiel) { 10754 guint8 n_fields = 0, ordering = 0; 10755 gst_byte_reader_get_uint8 (&br, &n_fields); 10756 gst_byte_reader_get_uint8 (&br, &ordering); 10757 if (n_fields == 1 || n_fields == 2) { 10758 GST_DEBUG_OBJECT (qtdemux, 10759 "Found fiel tag with %u fields, ordering %u", 10760 n_fields, ordering); 10761 if (n_fields == 2) 10762 gst_caps_set_simple (CUR_STREAM (stream)->caps, 10763 "interlace-mode", G_TYPE_STRING, "interleaved", 10764 NULL); 10765 } else { 10766 GST_WARNING_OBJECT (qtdemux, 10767 "Found fiel tag with invalid fields (%u)", n_fields); 10768 } 10769 } 10770 offset += size; 10771 } 10772 } else { 10773 GST_DEBUG_OBJECT (qtdemux, 10774 "Color table ID is 0, not trying to get interlacedness"); 10775 } 10776 } else { 10777 GST_WARNING_OBJECT (qtdemux, 10778 "Length of jpeg chunk is too small, not trying to get interlacedness"); 10779 } 10780 10781 break; 10782 } 10783 case FOURCC_rle_: 10784 case FOURCC_WRLE: 10785 { 10786 gst_caps_set_simple (entry->caps, 10787 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66), 10788 NULL); 10789 break; 10790 } 10791 case FOURCC_XiTh: 10792 { 10793 GNode *xith, *xdxt; 10794 10795 GST_DEBUG_OBJECT (qtdemux, "found XiTh"); 10796 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index); 10797 if (!xith) 10798 break; 10799 10800 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT); 10801 if (!xdxt) 10802 break; 10803 10804 GST_DEBUG_OBJECT (qtdemux, "found XdxT node"); 10805 /* collect the headers and store them in a stream list so that we can 10806 * send them out first */ 10807 qtdemux_parse_theora_extension (qtdemux, stream, xdxt); 10808 break; 10809 } 10810 case FOURCC_ovc1: 10811 { 10812 GNode *ovc1; 10813 guint8 *ovc1_data; 10814 guint ovc1_len; 10815 GstBuffer *buf; 10816 10817 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header"); 10818 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index); 10819 if (!ovc1) 10820 break; 10821 ovc1_data = ovc1->data; 10822 ovc1_len = QT_UINT32 (ovc1_data); 10823 if (ovc1_len <= 198) { 10824 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping"); 10825 break; 10826 } 10827 buf = gst_buffer_new_and_alloc (ovc1_len - 198); 10828 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198); 10829 gst_caps_set_simple (entry->caps, 10830 "codec_data", GST_TYPE_BUFFER, buf, NULL); 10831 gst_buffer_unref (buf); 10832 break; 10833 } 10834 case FOURCC_vc_1: 10835 { 10836 gint len = QT_UINT32 (stsd_entry_data) - 0x56; 10837 const guint8 *vc1_data = stsd_entry_data + 0x56; 10838 10839 /* find dvc1 */ 10840 while (len >= 8) { 10841 gint size; 10842 10843 if (QT_UINT32 (vc1_data) <= len) 10844 size = QT_UINT32 (vc1_data) - 8; 10845 else 10846 size = len - 8; 10847 10848 if (size < 1) 10849 /* No real data, so break out */ 10850 break; 10851 10852 switch (QT_FOURCC (vc1_data + 0x4)) { 10853 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'): 10854 { 10855 GstBuffer *buf; 10856 10857 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd"); 10858 buf = gst_buffer_new_and_alloc (size); 10859 gst_buffer_fill (buf, 0, vc1_data + 8, size); 10860 gst_caps_set_simple (entry->caps, 10861 "codec_data", GST_TYPE_BUFFER, buf, NULL); 10862 gst_buffer_unref (buf); 10863 break; 10864 } 10865 default: 10866 break; 10867 } 10868 len -= size + 8; 10869 vc1_data += size + 8; 10870 } 10871 break; 10872 } 10873 default: 10874 break; 10875 } 10876 } 10877 10878 GST_INFO_OBJECT (qtdemux, 10879 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT, 10880 GST_FOURCC_ARGS (fourcc), entry->caps); 10881 10882 } else if (stream->subtype == FOURCC_soun) { 10883 GNode *wave; 10884 int version, samplesize; 10885 guint16 compression_id; 10886 gboolean amrwb = FALSE; 10887 10888 offset = 16; 10889 /* sample description entry (16) + sound sample description v0 (20) */ 10890 if (len < 36) 10891 goto corrupt_file; 10892 10893 version = QT_UINT32 (stsd_entry_data + offset); 10894 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8); 10895 samplesize = QT_UINT16 (stsd_entry_data + offset + 10); 10896 compression_id = QT_UINT16 (stsd_entry_data + offset + 12); 10897 entry->rate = QT_FP32 (stsd_entry_data + offset + 16); 10898 10899 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version); 10900 GST_LOG_OBJECT (qtdemux, "vendor: %08x", 10901 QT_UINT32 (stsd_entry_data + offset + 4)); 10902 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels); 10903 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize); 10904 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id); 10905 GST_LOG_OBJECT (qtdemux, "packet size: %d", 10906 QT_UINT16 (stsd_entry_data + offset + 14)); 10907 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate); 10908 10909 if (compression_id == 0xfffe) 10910 entry->sampled = TRUE; 10911 10912 /* first assume uncompressed audio */ 10913 entry->bytes_per_sample = samplesize / 8; 10914 entry->samples_per_frame = entry->n_channels; 10915 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample; 10916 entry->samples_per_packet = entry->samples_per_frame; 10917 entry->bytes_per_packet = entry->bytes_per_sample; 10918 10919 offset = 36; 10920 switch (fourcc) { 10921 /* Yes, these have to be hard-coded */ 10922 case FOURCC_MAC6: 10923 { 10924 entry->samples_per_packet = 6; 10925 entry->bytes_per_packet = 1; 10926 entry->bytes_per_frame = 1 * entry->n_channels; 10927 entry->bytes_per_sample = 1; 10928 entry->samples_per_frame = 6 * entry->n_channels; 10929 break; 10930 } 10931 case FOURCC_MAC3: 10932 { 10933 entry->samples_per_packet = 3; 10934 entry->bytes_per_packet = 1; 10935 entry->bytes_per_frame = 1 * entry->n_channels; 10936 entry->bytes_per_sample = 1; 10937 entry->samples_per_frame = 3 * entry->n_channels; 10938 break; 10939 } 10940 case FOURCC_ima4: 10941 { 10942 entry->samples_per_packet = 64; 10943 entry->bytes_per_packet = 34; 10944 entry->bytes_per_frame = 34 * entry->n_channels; 10945 entry->bytes_per_sample = 2; 10946 entry->samples_per_frame = 64 * entry->n_channels; 10947 break; 10948 } 10949 case FOURCC_ulaw: 10950 case FOURCC_alaw: 10951 { 10952 entry->samples_per_packet = 1; 10953 entry->bytes_per_packet = 1; 10954 entry->bytes_per_frame = 1 * entry->n_channels; 10955 entry->bytes_per_sample = 1; 10956 entry->samples_per_frame = 1 * entry->n_channels; 10957 break; 10958 } 10959 case FOURCC_agsm: 10960 { 10961 entry->samples_per_packet = 160; 10962 entry->bytes_per_packet = 33; 10963 entry->bytes_per_frame = 33 * entry->n_channels; 10964 entry->bytes_per_sample = 2; 10965 entry->samples_per_frame = 160 * entry->n_channels; 10966 break; 10967 } 10968 default: 10969 break; 10970 } 10971 10972 if (version == 0x00010000) { 10973 /* sample description entry (16) + sound sample description v1 (20+16) */ 10974 if (len < 52) 10975 goto corrupt_file; 10976 10977 switch (fourcc) { 10978 case FOURCC_twos: 10979 case FOURCC_sowt: 10980 case FOURCC_raw_: 10981 case FOURCC_lpcm: 10982 break; 10983 default: 10984 { 10985 /* only parse extra decoding config for non-pcm audio */ 10986 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset); 10987 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4); 10988 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8); 10989 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12); 10990 10991 GST_LOG_OBJECT (qtdemux, "samples/packet: %d", 10992 entry->samples_per_packet); 10993 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d", 10994 entry->bytes_per_packet); 10995 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d", 10996 entry->bytes_per_frame); 10997 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d", 10998 entry->bytes_per_sample); 10999 11000 if (!entry->sampled && entry->bytes_per_packet) { 11001 entry->samples_per_frame = (entry->bytes_per_frame / 11002 entry->bytes_per_packet) * entry->samples_per_packet; 11003 GST_LOG_OBJECT (qtdemux, "samples/frame: %d", 11004 entry->samples_per_frame); 11005 } 11006 break; 11007 } 11008 } 11009 } else if (version == 0x00020000) { 11010 union 11011 { 11012 gdouble fp; 11013 guint64 val; 11014 } qtfp; 11015 11016 /* sample description entry (16) + sound sample description v2 (56) */ 11017 if (len < 72) 11018 goto corrupt_file; 11019 11020 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4); 11021 entry->rate = qtfp.fp; 11022 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12); 11023 11024 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2"); 11025 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate); 11026 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels); 11027 GST_LOG_OBJECT (qtdemux, "bits/channel: %d", 11028 QT_UINT32 (stsd_entry_data + offset + 20)); 11029 GST_LOG_OBJECT (qtdemux, "format flags: %X", 11030 QT_UINT32 (stsd_entry_data + offset + 24)); 11031 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d", 11032 QT_UINT32 (stsd_entry_data + offset + 28)); 11033 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d", 11034 QT_UINT32 (stsd_entry_data + offset + 32)); 11035 } else if (version != 0x00000) { 11036 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", 11037 version); 11038 } 11039 11040 if (entry->caps) 11041 gst_caps_unref (entry->caps); 11042 11043 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc, 11044 stsd_entry_data + 32, len - 16, &codec); 11045 11046 switch (fourcc) { 11047 case FOURCC_in24: 11048 { 11049 GNode *enda; 11050 GNode *in24; 11051 11052 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24); 11053 11054 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda); 11055 if (!enda) { 11056 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave); 11057 if (wave) 11058 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda); 11059 } 11060 if (enda) { 11061 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8); 11062 gst_caps_set_simple (entry->caps, 11063 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", 11064 NULL); 11065 } 11066 break; 11067 } 11068 case FOURCC_owma: 11069 { 11070 const guint8 *owma_data; 11071 const gchar *codec_name = NULL; 11072 guint owma_len; 11073 GstBuffer *buf; 11074 gint version = 1; 11075 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */ 11076 /* FIXME this should also be gst_riff_strf_auds, 11077 * but the latter one is actually missing bits-per-sample :( */ 11078 typedef struct 11079 { 11080 gint16 wFormatTag; 11081 gint16 nChannels; 11082 gint32 nSamplesPerSec; 11083 gint32 nAvgBytesPerSec; 11084 gint16 nBlockAlign; 11085 gint16 wBitsPerSample; 11086 gint16 cbSize; 11087 } WAVEFORMATEX; 11088 WAVEFORMATEX *wfex; 11089 11090 GST_DEBUG_OBJECT (qtdemux, "parse owma"); 11091 owma_data = stsd_entry_data; 11092 owma_len = QT_UINT32 (owma_data); 11093 if (owma_len <= 54) { 11094 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping"); 11095 break; 11096 } 11097 wfex = (WAVEFORMATEX *) (owma_data + 36); 11098 buf = gst_buffer_new_and_alloc (owma_len - 54); 11099 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54); 11100 if (wfex->wFormatTag == 0x0161) { 11101 codec_name = "Windows Media Audio"; 11102 version = 2; 11103 } else if (wfex->wFormatTag == 0x0162) { 11104 codec_name = "Windows Media Audio 9 Pro"; 11105 version = 3; 11106 } else if (wfex->wFormatTag == 0x0163) { 11107 codec_name = "Windows Media Audio 9 Lossless"; 11108 /* is that correct? gstffmpegcodecmap.c is missing it, but 11109 * fluendo codec seems to support it */ 11110 version = 4; 11111 } 11112 11113 gst_caps_set_simple (entry->caps, 11114 "codec_data", GST_TYPE_BUFFER, buf, 11115 "wmaversion", G_TYPE_INT, version, 11116 "block_align", G_TYPE_INT, 11117 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT, 11118 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT, 11119 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT, 11120 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL); 11121 gst_buffer_unref (buf); 11122 11123 if (codec_name) { 11124 g_free (codec); 11125 codec = g_strdup (codec_name); 11126 } 11127 break; 11128 } 11129 case FOURCC_wma_: 11130 { 11131 gint len = QT_UINT32 (stsd_entry_data) - offset; 11132 const guint8 *wfex_data = stsd_entry_data + offset; 11133 const gchar *codec_name = NULL; 11134 gint version = 1; 11135 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */ 11136 /* FIXME this should also be gst_riff_strf_auds, 11137 * but the latter one is actually missing bits-per-sample :( */ 11138 typedef struct 11139 { 11140 gint16 wFormatTag; 11141 gint16 nChannels; 11142 gint32 nSamplesPerSec; 11143 gint32 nAvgBytesPerSec; 11144 gint16 nBlockAlign; 11145 gint16 wBitsPerSample; 11146 gint16 cbSize; 11147 } WAVEFORMATEX; 11148 WAVEFORMATEX wfex; 11149 11150 /* FIXME: unify with similar wavformatex parsing code above */ 11151 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex"); 11152 11153 /* find wfex */ 11154 while (len >= 8) { 11155 gint size; 11156 11157 if (QT_UINT32 (wfex_data) <= len) 11158 size = QT_UINT32 (wfex_data) - 8; 11159 else 11160 size = len - 8; 11161 11162 if (size < 1) 11163 /* No real data, so break out */ 11164 break; 11165 11166 switch (QT_FOURCC (wfex_data + 4)) { 11167 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'): 11168 { 11169 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd"); 11170 11171 if (size < 8 + 18) 11172 break; 11173 11174 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0); 11175 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2); 11176 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4); 11177 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8); 11178 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12); 11179 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14); 11180 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16); 11181 11182 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:"); 11183 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, " 11184 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, " 11185 "BitsPerSample = %u, Size = %u", wfex.wFormatTag, 11186 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec, 11187 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize); 11188 11189 if (wfex.wFormatTag == 0x0161) { 11190 codec_name = "Windows Media Audio"; 11191 version = 2; 11192 } else if (wfex.wFormatTag == 0x0162) { 11193 codec_name = "Windows Media Audio 9 Pro"; 11194 version = 3; 11195 } else if (wfex.wFormatTag == 0x0163) { 11196 codec_name = "Windows Media Audio 9 Lossless"; 11197 /* is that correct? gstffmpegcodecmap.c is missing it, but 11198 * fluendo codec seems to support it */ 11199 version = 4; 11200 } 11201 11202 gst_caps_set_simple (entry->caps, 11203 "wmaversion", G_TYPE_INT, version, 11204 "block_align", G_TYPE_INT, wfex.nBlockAlign, 11205 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec, 11206 "width", G_TYPE_INT, wfex.wBitsPerSample, 11207 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL); 11208 11209 if (size > wfex.cbSize) { 11210 GstBuffer *buf; 11211 11212 buf = gst_buffer_new_and_alloc (size - wfex.cbSize); 11213 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize, 11214 size - wfex.cbSize); 11215 gst_caps_set_simple (entry->caps, 11216 "codec_data", GST_TYPE_BUFFER, buf, NULL); 11217 gst_buffer_unref (buf); 11218 } else { 11219 GST_WARNING_OBJECT (qtdemux, "no codec data"); 11220 } 11221 11222 if (codec_name) { 11223 g_free (codec); 11224 codec = g_strdup (codec_name); 11225 } 11226 break; 11227 } 11228 default: 11229 break; 11230 } 11231 len -= size + 8; 11232 wfex_data += size + 8; 11233 } 11234 break; 11235 } 11236 #ifndef GSTREAMER_LITE 11237 case FOURCC_opus: 11238 { 11239 const guint8 *opus_data; 11240 guint8 *channel_mapping = NULL; 11241 guint32 rate; 11242 guint8 channels; 11243 guint8 channel_mapping_family; 11244 guint8 stream_count; 11245 guint8 coupled_count; 11246 guint8 i; 11247 11248 opus_data = stsd_entry_data; 11249 11250 channels = GST_READ_UINT8 (opus_data + 45); 11251 rate = GST_READ_UINT32_LE (opus_data + 48); 11252 channel_mapping_family = GST_READ_UINT8 (opus_data + 54); 11253 stream_count = GST_READ_UINT8 (opus_data + 55); 11254 coupled_count = GST_READ_UINT8 (opus_data + 56); 11255 11256 if (channels > 0) { 11257 channel_mapping = g_malloc (channels * sizeof (guint8)); 11258 for (i = 0; i < channels; i++) 11259 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57); 11260 } 11261 11262 entry->caps = gst_codec_utils_opus_create_caps (rate, channels, 11263 channel_mapping_family, stream_count, coupled_count, 11264 channel_mapping); 11265 break; 11266 } 11267 #endif // GSTREAMER_LITE 11268 default: 11269 break; 11270 } 11271 11272 if (codec) { 11273 GstStructure *s; 11274 gint bitrate = 0; 11275 11276 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE, 11277 GST_TAG_AUDIO_CODEC, codec, NULL); 11278 g_free (codec); 11279 codec = NULL; 11280 11281 /* some bitrate info may have ended up in caps */ 11282 s = gst_caps_get_structure (entry->caps, 0); 11283 gst_structure_get_int (s, "bitrate", &bitrate); 11284 if (bitrate > 0) 11285 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE, 11286 GST_TAG_BITRATE, bitrate, NULL); 11287 } 11288 11289 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index); 11290 if (!stream->protected) { 11291 } else { 11292 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) { 11293 mp4v = NULL; 11294 } 11295 } 11296 if (stream->protected && fourcc == FOURCC_mp4a) { 11297 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) { 11298 mp4a = NULL; 11299 } 11300 } else { 11301 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) { 11302 mp4a = NULL; 11303 } 11304 } 11305 11306 wave = NULL; 11307 esds = NULL; 11308 if (mp4a) { 11309 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave); 11310 if (wave) 11311 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds); 11312 if (!esds) 11313 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds); 11314 } 11315 11316 11317 /* If the fourcc's bottom 16 bits gives 'sm', then the top 11318 16 bits is a byte-swapped wave-style codec identifier, 11319 and we can find a WAVE header internally to a 'wave' atom here. 11320 This can more clearly be thought of as 'ms' as the top 16 bits, and a 11321 codec id as the bottom 16 bits - but byte-swapped to store in QT (which 11322 is big-endian). 11323 */ 11324 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) { 11325 if (len < offset + 20) { 11326 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio"); 11327 } else { 11328 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16); 11329 const guint8 *data = stsd_entry_data + offset + 16; 11330 GNode *wavenode; 11331 GNode *waveheadernode; 11332 11333 wavenode = g_node_new ((guint8 *) data); 11334 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) { 11335 const guint8 *waveheader; 11336 guint32 headerlen; 11337 11338 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc); 11339 if (waveheadernode) { 11340 waveheader = (const guint8 *) waveheadernode->data; 11341 headerlen = QT_UINT32 (waveheader); 11342 11343 if (headerlen > 8) { 11344 gst_riff_strf_auds *header = NULL; 11345 GstBuffer *headerbuf; 11346 GstBuffer *extra; 11347 11348 waveheader += 8; 11349 headerlen -= 8; 11350 11351 headerbuf = gst_buffer_new_and_alloc (headerlen); 11352 gst_buffer_fill (headerbuf, 0, waveheader, headerlen); 11353 11354 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux), 11355 headerbuf, &header, &extra)) { 11356 gst_caps_unref (entry->caps); 11357 /* FIXME: Need to do something with the channel reorder map */ 11358 entry->caps = 11359 gst_riff_create_audio_caps (header->format, NULL, header, 11360 extra, NULL, NULL, NULL); 11361 11362 if (extra) 11363 gst_buffer_unref (extra); 11364 g_free (header); 11365 } 11366 } 11367 } else 11368 GST_DEBUG ("Didn't find waveheadernode for this codec"); 11369 } 11370 g_node_destroy (wavenode); 11371 } 11372 } else if (esds) { 11373 #ifdef GSTREAMER_LITE 11374 if (!gst_qtdemux_handle_esds (qtdemux, stream, entry, esds, 11375 stream->stream_tags)) 11376 goto corrupt_file; 11377 #else 11378 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds, 11379 stream->stream_tags); 11380 #endif // GSTREAMER_LITE 11381 } else { 11382 switch (fourcc) { 11383 #if 0 11384 /* FIXME: what is in the chunk? */ 11385 case FOURCC_QDMC: 11386 { 11387 gint len = QT_UINT32 (stsd_data); 11388 11389 /* seems to be always = 116 = 0x74 */ 11390 break; 11391 } 11392 #endif 11393 case FOURCC_QDM2: 11394 { 11395 gint len = QT_UINT32 (stsd_entry_data); 11396 11397 if (len > 0x3C) { 11398 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C); 11399 11400 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C); 11401 gst_caps_set_simple (entry->caps, 11402 "codec_data", GST_TYPE_BUFFER, buf, NULL); 11403 gst_buffer_unref (buf); 11404 } 11405 gst_caps_set_simple (entry->caps, 11406 "samplesize", G_TYPE_INT, samplesize, NULL); 11407 break; 11408 } 11409 case FOURCC_alac: 11410 { 11411 GNode *alac, *wave = NULL; 11412 11413 /* apparently, m4a has this atom appended directly in the stsd entry, 11414 * while mov has it in a wave atom */ 11415 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac); 11416 if (alac) { 11417 /* alac now refers to stsd entry atom */ 11418 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave); 11419 if (wave) 11420 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac); 11421 else 11422 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac); 11423 } 11424 if (alac) { 11425 const guint8 *alac_data = alac->data; 11426 gint len = QT_UINT32 (alac->data); 11427 GstBuffer *buf; 11428 11429 if (len < 36) { 11430 GST_DEBUG_OBJECT (qtdemux, 11431 "discarding alac atom with unexpected len %d", len); 11432 } else { 11433 /* codec-data contains alac atom size and prefix, 11434 * ffmpeg likes it that way, not quite gst-ish though ...*/ 11435 buf = gst_buffer_new_and_alloc (len); 11436 gst_buffer_fill (buf, 0, alac->data, len); 11437 gst_caps_set_simple (entry->caps, 11438 "codec_data", GST_TYPE_BUFFER, buf, NULL); 11439 gst_buffer_unref (buf); 11440 11441 entry->bytes_per_frame = QT_UINT32 (alac_data + 12); 11442 entry->n_channels = QT_UINT8 (alac_data + 21); 11443 entry->rate = QT_UINT32 (alac_data + 32); 11444 } 11445 } 11446 gst_caps_set_simple (entry->caps, 11447 "samplesize", G_TYPE_INT, samplesize, NULL); 11448 break; 11449 } 11450 case FOURCC_fLaC: 11451 { 11452 /* The codingname of the sample entry is 'fLaC' */ 11453 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC); 11454 11455 if (flac) { 11456 /* The 'dfLa' box is added to the sample entry to convey 11457 initializing information for the decoder. */ 11458 const GNode *dfla = 11459 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa); 11460 11461 if (dfla) { 11462 const guint32 len = QT_UINT32 (dfla->data); 11463 11464 /* Must contain at least dfLa box header (12), 11465 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */ 11466 if (len < 50) { 11467 GST_DEBUG_OBJECT (qtdemux, 11468 "discarding dfla atom with unexpected len %d", len); 11469 } else { 11470 /* skip dfLa header to get the METADATA_BLOCKs */ 11471 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12; 11472 const guint32 metadata_blocks_len = len - 12; 11473 11474 gchar *stream_marker = g_strdup ("fLaC"); 11475 GstBuffer *block = gst_buffer_new_wrapped (stream_marker, 11476 strlen (stream_marker)); 11477 11478 guint32 index = 0; 11479 guint32 remainder = 0; 11480 guint32 block_size = 0; 11481 gboolean is_last = FALSE; 11482 11483 GValue array = G_VALUE_INIT; 11484 GValue value = G_VALUE_INIT; 11485 11486 g_value_init (&array, GST_TYPE_ARRAY); 11487 g_value_init (&value, GST_TYPE_BUFFER); 11488 11489 gst_value_set_buffer (&value, block); 11490 gst_value_array_append_value (&array, &value); 11491 g_value_reset (&value); 11492 11493 gst_buffer_unref (block); 11494 11495 /* check there's at least one METADATA_BLOCK_HEADER's worth 11496 * of data, and we haven't already finished parsing */ 11497 while (!is_last && ((index + 3) < metadata_blocks_len)) { 11498 remainder = metadata_blocks_len - index; 11499 11500 /* add the METADATA_BLOCK_HEADER size to the signalled size */ 11501 block_size = 4 + 11502 (metadata_blocks[index + 1] << 16) + 11503 (metadata_blocks[index + 2] << 8) + 11504 metadata_blocks[index + 3]; 11505 11506 /* be careful not to read off end of box */ 11507 if (block_size > remainder) { 11508 break; 11509 } 11510 11511 is_last = metadata_blocks[index] >> 7; 11512 11513 block = gst_buffer_new_and_alloc (block_size); 11514 11515 gst_buffer_fill (block, 0, &metadata_blocks[index], 11516 block_size); 11517 11518 gst_value_set_buffer (&value, block); 11519 gst_value_array_append_value (&array, &value); 11520 g_value_reset (&value); 11521 11522 gst_buffer_unref (block); 11523 11524 index += block_size; 11525 } 11526 11527 /* only append the metadata if we successfully read all of it */ 11528 if (is_last) { 11529 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM 11530 (stream)->caps, 0), "streamheader", &array); 11531 } else { 11532 GST_WARNING_OBJECT (qtdemux, 11533 "discarding all METADATA_BLOCKs due to invalid " 11534 "block_size %d at idx %d, rem %d", block_size, index, 11535 remainder); 11536 } 11537 11538 g_value_unset (&value); 11539 g_value_unset (&array); 11540 11541 /* The sample rate obtained from the stsd may not be accurate 11542 * since it cannot represent rates greater than 65535Hz, so 11543 * override that value with the sample rate from the 11544 * METADATA_BLOCK_STREAMINFO block */ 11545 CUR_STREAM (stream)->rate = 11546 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF; 11547 } 11548 } 11549 } 11550 break; 11551 } 11552 case FOURCC_sawb: 11553 /* Fallthrough! */ 11554 amrwb = TRUE; 11555 case FOURCC_samr: 11556 { 11557 gint len = QT_UINT32 (stsd_entry_data); 11558 11559 if (len > 0x24) { 11560 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24); 11561 guint bitrate; 11562 11563 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24); 11564 11565 /* If we have enough data, let's try to get the 'damr' atom. See 11566 * the 3GPP container spec (26.244) for more details. */ 11567 if ((len - 0x34) > 8 && 11568 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) { 11569 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE, 11570 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL); 11571 } 11572 11573 gst_caps_set_simple (entry->caps, 11574 "codec_data", GST_TYPE_BUFFER, buf, NULL); 11575 gst_buffer_unref (buf); 11576 } 11577 break; 11578 } 11579 case FOURCC_mp4a: 11580 { 11581 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */ 11582 gint len = QT_UINT32 (stsd_entry_data); 11583 11584 if (len >= 34) { 11585 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16); 11586 11587 if (sound_version == 1) { 11588 guint16 channels = QT_UINT16 (stsd_entry_data + 24); 11589 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30); 11590 guint8 codec_data[2]; 11591 GstBuffer *buf; 11592 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */ 11593 11594 gint sample_rate_index = 11595 gst_codec_utils_aac_get_index_from_sample_rate (time_scale); 11596 11597 /* build AAC codec data */ 11598 codec_data[0] = profile << 3; 11599 codec_data[0] |= ((sample_rate_index >> 1) & 0x7); 11600 codec_data[1] = (sample_rate_index & 0x01) << 7; 11601 codec_data[1] |= (channels & 0xF) << 3; 11602 11603 buf = gst_buffer_new_and_alloc (2); 11604 gst_buffer_fill (buf, 0, codec_data, 2); 11605 gst_caps_set_simple (entry->caps, 11606 "codec_data", GST_TYPE_BUFFER, buf, NULL); 11607 gst_buffer_unref (buf); 11608 } 11609 } 11610 break; 11611 } 11612 case FOURCC_lpcm: 11613 /* Fully handled elsewhere */ 11614 break; 11615 default: 11616 GST_INFO_OBJECT (qtdemux, 11617 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc)); 11618 break; 11619 } 11620 } 11621 GST_INFO_OBJECT (qtdemux, 11622 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT, 11623 GST_FOURCC_ARGS (fourcc), entry->caps); 11624 11625 } else if (stream->subtype == FOURCC_strm) { 11626 if (fourcc == FOURCC_rtsp) { 11627 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf); 11628 } else { 11629 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT, 11630 GST_FOURCC_ARGS (fourcc)); 11631 goto unknown_stream; 11632 } 11633 entry->sampled = TRUE; 11634 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text 11635 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) { 11636 11637 entry->sampled = TRUE; 11638 entry->sparse = TRUE; 11639 11640 entry->caps = 11641 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data, 11642 &codec); 11643 if (codec) { 11644 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE, 11645 GST_TAG_SUBTITLE_CODEC, codec, NULL); 11646 g_free (codec); 11647 codec = NULL; 11648 } 11649 11650 /* hunt for sort-of codec data */ 11651 switch (fourcc) { 11652 case FOURCC_mp4s: 11653 { 11654 GNode *mp4s = NULL; 11655 GNode *esds = NULL; 11656 11657 /* look for palette in a stsd->mp4s->esds sub-atom */ 11658 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s); 11659 if (mp4s) 11660 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds); 11661 if (esds == NULL) { 11662 /* Invalid STSD */ 11663 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child"); 11664 break; 11665 } 11666 11667 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds, 11668 stream->stream_tags); 11669 break; 11670 } 11671 default: 11672 GST_INFO_OBJECT (qtdemux, 11673 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc)); 11674 break; 11675 } 11676 GST_INFO_OBJECT (qtdemux, 11677 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT, 11678 GST_FOURCC_ARGS (fourcc), entry->caps); 11679 } else { 11680 /* everything in 1 sample */ 11681 entry->sampled = TRUE; 11682 11683 entry->caps = 11684 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data, 11685 &codec); 11686 11687 if (entry->caps == NULL) 11688 goto unknown_stream; 11689 11690 if (codec) { 11691 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE, 11692 GST_TAG_SUBTITLE_CODEC, codec, NULL); 11693 g_free (codec); 11694 codec = NULL; 11695 } 11696 } 11697 11698 /* promote to sampled format */ 11699 if (entry->fourcc == FOURCC_samr) { 11700 /* force mono 8000 Hz for AMR */ 11701 entry->sampled = TRUE; 11702 entry->n_channels = 1; 11703 entry->rate = 8000; 11704 } else if (entry->fourcc == FOURCC_sawb) { 11705 /* force mono 16000 Hz for AMR-WB */ 11706 entry->sampled = TRUE; 11707 entry->n_channels = 1; 11708 entry->rate = 16000; 11709 } else if (entry->fourcc == FOURCC_mp4a) { 11710 entry->sampled = TRUE; 11711 } 11712 11713 11714 stsd_entry_data += len; 11715 remaining_stsd_len -= len; 11716 11717 } 11718 11719 /* collect sample information */ 11720 if (!qtdemux_stbl_init (qtdemux, stream, stbl)) 11721 goto samples_failed; 11722 11723 if (qtdemux->fragmented) { 11724 guint64 offset; 11725 11726 /* need all moov samples as basis; probably not many if any at all */ 11727 /* prevent moof parsing taking of at this time */ 11728 offset = qtdemux->moof_offset; 11729 qtdemux->moof_offset = 0; 11730 if (stream->n_samples && 11731 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) { 11732 qtdemux->moof_offset = offset; 11733 goto samples_failed; 11734 } 11735 qtdemux->moof_offset = 0; 11736 /* movie duration more reliable in this case (e.g. mehd) */ 11737 if (qtdemux->segment.duration && 11738 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration)) 11739 stream->duration = 11740 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration); 11741 } 11742 11743 /* configure segments */ 11744 if (!qtdemux_parse_segments (qtdemux, stream, trak)) 11745 goto segments_failed; 11746 11747 /* add some language tag, if useful */ 11748 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") && 11749 strcmp (stream->lang_id, "und")) { 11750 const gchar *lang_code; 11751 11752 /* convert ISO 639-2 code to ISO 639-1 */ 11753 lang_code = gst_tag_get_language_code (stream->lang_id); 11754 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE, 11755 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL); 11756 } 11757 11758 /* Check for UDTA tags */ 11759 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) { 11760 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta); 11761 } 11762 11763 /* now we are ready to add the stream */ 11764 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS) 11765 goto too_many_streams; 11766 11767 if (!qtdemux->got_moov) { 11768 qtdemux->streams[qtdemux->n_streams] = stream; 11769 qtdemux->n_streams++; 11770 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams); 11771 } 11772 11773 return TRUE; 11774 11775 /* ERRORS */ 11776 skip_track: 11777 { 11778 GST_INFO_OBJECT (qtdemux, "skip disabled track"); 11779 if (new_stream) 11780 gst_qtdemux_stream_free (qtdemux, stream); 11781 return TRUE; 11782 } 11783 corrupt_file: 11784 { 11785 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX, 11786 (_("This file is corrupt and cannot be played.")), (NULL)); 11787 if (new_stream) 11788 gst_qtdemux_stream_free (qtdemux, stream); 11789 return FALSE; 11790 } 11791 error_encrypted: 11792 { 11793 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL)); 11794 if (new_stream) 11795 gst_qtdemux_stream_free (qtdemux, stream); 11796 return FALSE; 11797 } 11798 samples_failed: 11799 segments_failed: 11800 { 11801 /* we posted an error already */ 11802 /* free stbl sub-atoms */ 11803 gst_qtdemux_stbl_free (stream); 11804 if (new_stream) 11805 gst_qtdemux_stream_free (qtdemux, stream); 11806 return FALSE; 11807 } 11808 existing_stream: 11809 { 11810 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists", 11811 track_id); 11812 if (new_stream) 11813 gst_qtdemux_stream_free (qtdemux, stream); 11814 return TRUE; 11815 } 11816 unknown_stream: 11817 { 11818 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT, 11819 GST_FOURCC_ARGS (stream->subtype)); 11820 if (new_stream) 11821 gst_qtdemux_stream_free (qtdemux, stream); 11822 return TRUE; 11823 } 11824 too_many_streams: 11825 { 11826 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX, 11827 (_("This file contains too many streams. Only playing first %d"), 11828 GST_QTDEMUX_MAX_STREAMS), (NULL)); 11829 return TRUE; 11830 } 11831 } 11832 11833 /* If we can estimate the overall bitrate, and don't have information about the 11834 * stream bitrate for exactly one stream, this guesses the stream bitrate as 11835 * the overall bitrate minus the sum of the bitrates of all other streams. This 11836 * should be useful for the common case where we have one audio and one video 11837 * stream and can estimate the bitrate of one, but not the other. */ 11838 static void 11839 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux) 11840 { 11841 QtDemuxStream *stream = NULL; 11842 gint64 size, sys_bitrate, sum_bitrate = 0; 11843 GstClockTime duration; 11844 gint i; 11845 guint bitrate; 11846 11847 if (qtdemux->fragmented) 11848 return; 11849 11850 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate"); 11851 11852 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size) 11853 || size <= 0) { 11854 GST_DEBUG_OBJECT (qtdemux, 11855 "Size in bytes of the stream not known - bailing"); 11856 return; 11857 } 11858 11859 /* Subtract the header size */ 11860 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u", 11861 size, qtdemux->header_size); 11862 11863 if (size < qtdemux->header_size) 11864 return; 11865 11866 size = size - qtdemux->header_size; 11867 11868 if (!gst_qtdemux_get_duration (qtdemux, &duration)) { 11869 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing"); 11870 return; 11871 } 11872 11873 for (i = 0; i < qtdemux->n_streams; i++) { 11874 switch (qtdemux->streams[i]->subtype) { 11875 case FOURCC_soun: 11876 case FOURCC_vide: 11877 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT, 11878 CUR_STREAM (qtdemux->streams[i])->caps); 11879 /* retrieve bitrate, prefer avg then max */ 11880 bitrate = 0; 11881 if (qtdemux->streams[i]->stream_tags) { 11882 if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags, 11883 GST_TAG_MAXIMUM_BITRATE, &bitrate)) 11884 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate); 11885 if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags, 11886 GST_TAG_NOMINAL_BITRATE, &bitrate)) 11887 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate); 11888 if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags, 11889 GST_TAG_BITRATE, &bitrate)) 11890 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate); 11891 } 11892 if (bitrate) 11893 sum_bitrate += bitrate; 11894 else { 11895 if (stream) { 11896 GST_DEBUG_OBJECT (qtdemux, 11897 ">1 stream with unknown bitrate - bailing"); 11898 return; 11899 } else 11900 stream = qtdemux->streams[i]; 11901 } 11902 11903 default: 11904 /* For other subtypes, we assume no significant impact on bitrate */ 11905 break; 11906 } 11907 } 11908 11909 if (!stream) { 11910 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known"); 11911 return; 11912 } 11913 11914 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration); 11915 11916 if (sys_bitrate < sum_bitrate) { 11917 /* This can happen, since sum_bitrate might be derived from maximum 11918 * bitrates and not average bitrates */ 11919 GST_DEBUG_OBJECT (qtdemux, 11920 "System bitrate less than sum bitrate - bailing"); 11921 return; 11922 } 11923 11924 bitrate = sys_bitrate - sum_bitrate; 11925 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT 11926 ", Stream bitrate = %u", sys_bitrate, bitrate); 11927 11928 if (!stream->stream_tags) 11929 stream->stream_tags = gst_tag_list_new_empty (); 11930 else 11931 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags); 11932 11933 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE, 11934 GST_TAG_BITRATE, bitrate, NULL); 11935 } 11936 11937 static GstFlowReturn 11938 qtdemux_prepare_streams (GstQTDemux * qtdemux) 11939 { 11940 gint i; 11941 GstFlowReturn ret = GST_FLOW_OK; 11942 11943 GST_DEBUG_OBJECT (qtdemux, "prepare streams"); 11944 11945 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) { 11946 QtDemuxStream *stream = qtdemux->streams[i]; 11947 guint32 sample_num = 0; 11948 11949 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT, 11950 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc)); 11951 11952 if (qtdemux->fragmented) { 11953 /* need all moov samples first */ 11954 GST_OBJECT_LOCK (qtdemux); 11955 while (stream->n_samples == 0) 11956 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK) 11957 break; 11958 GST_OBJECT_UNLOCK (qtdemux); 11959 } else { 11960 /* discard any stray moof */ 11961 qtdemux->moof_offset = 0; 11962 } 11963 11964 /* prepare braking */ 11965 if (ret != GST_FLOW_ERROR) 11966 ret = GST_FLOW_OK; 11967 11968 /* in pull mode, we should have parsed some sample info by now; 11969 * and quite some code will not handle no samples. 11970 * in push mode, we'll just have to deal with it */ 11971 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) { 11972 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding"); 11973 gst_qtdemux_remove_stream (qtdemux, i); 11974 i--; 11975 continue; 11976 } 11977 11978 /* parse the initial sample for use in setting the frame rate cap */ 11979 while (sample_num == 0 && sample_num < stream->n_samples) { 11980 if (!qtdemux_parse_samples (qtdemux, stream, sample_num)) 11981 break; 11982 ++sample_num; 11983 } 11984 if (stream->n_samples > 0 && stream->stbl_index >= 0) { 11985 stream->first_duration = stream->samples[0].duration; 11986 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u", 11987 stream->track_id, stream->first_duration); 11988 } 11989 } 11990 11991 return ret; 11992 } 11993 11994 static GstFlowReturn 11995 qtdemux_expose_streams (GstQTDemux * qtdemux) 11996 { 11997 gint i; 11998 GSList *oldpads = NULL; 11999 GSList *iter; 12000 12001 GST_DEBUG_OBJECT (qtdemux, "exposing streams"); 12002 12003 for (i = 0; i < qtdemux->n_streams; i++) { 12004 QtDemuxStream *stream = qtdemux->streams[i]; 12005 GstPad *oldpad = stream->pad; 12006 GstTagList *list; 12007 12008 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT, 12009 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc)); 12010 12011 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) && 12012 stream->track_id == qtdemux->chapters_track_id) { 12013 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it 12014 so that it doesn't look like a subtitle track */ 12015 gst_qtdemux_remove_stream (qtdemux, i); 12016 i--; 12017 continue; 12018 } 12019 12020 /* now we have all info and can expose */ 12021 list = stream->stream_tags; 12022 stream->stream_tags = NULL; 12023 if (oldpad) 12024 oldpads = g_slist_prepend (oldpads, oldpad); 12025 if (!gst_qtdemux_add_stream (qtdemux, stream, list)) 12026 return GST_FLOW_ERROR; 12027 } 12028 12029 gst_qtdemux_guess_bitrate (qtdemux); 12030 12031 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux)); 12032 12033 for (iter = oldpads; iter; iter = g_slist_next (iter)) { 12034 GstPad *oldpad = iter->data; 12035 GstEvent *event; 12036 12037 event = gst_event_new_eos (); 12038 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) 12039 gst_event_set_seqnum (event, qtdemux->segment_seqnum); 12040 12041 gst_pad_push_event (oldpad, event); 12042 gst_pad_set_active (oldpad, FALSE); 12043 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad); 12044 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad); 12045 gst_object_unref (oldpad); 12046 } 12047 12048 /* check if we should post a redirect in case there is a single trak 12049 * and it is a redirecting trak */ 12050 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) { 12051 GstMessage *m; 12052 12053 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with " 12054 "an external content"); 12055 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux), 12056 gst_structure_new ("redirect", 12057 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri, 12058 NULL)); 12059 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m); 12060 qtdemux->posted_redirect = TRUE; 12061 } 12062 12063 for (i = 0; i < qtdemux->n_streams; i++) { 12064 QtDemuxStream *stream = qtdemux->streams[i]; 12065 12066 qtdemux_do_allocation (qtdemux, stream); 12067 } 12068 12069 qtdemux->exposed = TRUE; 12070 return GST_FLOW_OK; 12071 } 12072 12073 /* check if major or compatible brand is 3GP */ 12074 static inline gboolean 12075 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major) 12076 { 12077 if (major) { 12078 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) == 12079 FOURCC_3g__); 12080 } else if (qtdemux->comp_brands != NULL) { 12081 GstMapInfo map; 12082 guint8 *data; 12083 gsize size; 12084 gboolean res = FALSE; 12085 12086 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ); 12087 data = map.data; 12088 size = map.size; 12089 while (size >= 4) { 12090 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) == 12091 FOURCC_3g__); 12092 data += 4; 12093 size -= 4; 12094 } 12095 gst_buffer_unmap (qtdemux->comp_brands, &map); 12096 return res; 12097 } else { 12098 return FALSE; 12099 } 12100 } 12101 12102 /* check if tag is a spec'ed 3GP tag keyword storing a string */ 12103 static inline gboolean 12104 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc) 12105 { 12106 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl 12107 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth 12108 || fourcc == FOURCC_albm; 12109 } 12110 12111 static void 12112 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist, 12113 const char *tag, const char *dummy, GNode * node) 12114 { 12115 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; 12116 int offset; 12117 char *name; 12118 gchar *data; 12119 gdouble longitude, latitude, altitude; 12120 gint len; 12121 12122 len = QT_UINT32 (node->data); 12123 if (len <= 14) 12124 goto short_read; 12125 12126 data = node->data; 12127 offset = 14; 12128 12129 /* TODO: language code skipped */ 12130 12131 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars); 12132 12133 if (!name) { 12134 /* do not alarm in trivial case, but bail out otherwise */ 12135 if (*(data + offset) != 0) { 12136 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, " 12137 "giving up", tag); 12138 } 12139 } else { 12140 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, 12141 GST_TAG_GEO_LOCATION_NAME, name, NULL); 12142 offset += strlen (name); 12143 g_free (name); 12144 } 12145 12146 if (len < offset + 2 + 4 + 4 + 4) 12147 goto short_read; 12148 12149 /* +1 +1 = skip null-terminator and location role byte */ 12150 offset += 1 + 1; 12151 /* table in spec says unsigned, semantics say negative has meaning ... */ 12152 longitude = QT_SFP32 (data + offset); 12153 12154 offset += 4; 12155 latitude = QT_SFP32 (data + offset); 12156 12157 offset += 4; 12158 altitude = QT_SFP32 (data + offset); 12159 12160 /* one invalid means all are invalid */ 12161 if (longitude >= -180.0 && longitude <= 180.0 && 12162 latitude >= -90.0 && latitude <= 90.0) { 12163 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, 12164 GST_TAG_GEO_LOCATION_LATITUDE, latitude, 12165 GST_TAG_GEO_LOCATION_LONGITUDE, longitude, 12166 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL); 12167 } 12168 12169 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */ 12170 12171 return; 12172 12173 /* ERRORS */ 12174 short_read: 12175 { 12176 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location"); 12177 return; 12178 } 12179 } 12180 12181 12182 static void 12183 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist, 12184 const char *tag, const char *dummy, GNode * node) 12185 { 12186 guint16 y; 12187 GDate *date; 12188 gint len; 12189 12190 len = QT_UINT32 (node->data); 12191 if (len < 14) 12192 return; 12193 12194 y = QT_UINT16 ((guint8 *) node->data + 12); 12195 if (y == 0) { 12196 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y); 12197 return; 12198 } 12199 GST_DEBUG_OBJECT (qtdemux, "year: %u", y); 12200 12201 date = g_date_new_dmy (1, 1, y); 12202 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL); 12203 g_date_free (date); 12204 } 12205 12206 static void 12207 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist, 12208 const char *tag, const char *dummy, GNode * node) 12209 { 12210 int offset; 12211 char *tag_str = NULL; 12212 guint8 *entity; 12213 guint16 table; 12214 gint len; 12215 12216 len = QT_UINT32 (node->data); 12217 if (len <= 20) 12218 goto short_read; 12219 12220 offset = 12; 12221 entity = (guint8 *) node->data + offset; 12222 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) { 12223 GST_DEBUG_OBJECT (qtdemux, 12224 "classification info: %c%c%c%c invalid classification entity", 12225 entity[0], entity[1], entity[2], entity[3]); 12226 return; 12227 } 12228 12229 offset += 4; 12230 table = QT_UINT16 ((guint8 *) node->data + offset); 12231 12232 /* Language code skipped */ 12233 12234 offset += 4; 12235 12236 /* Tag format: "XXXX://Y[YYYY]/classification info string" 12237 * XXXX: classification entity, fixed length 4 chars. 12238 * Y[YYYY]: classification table, max 5 chars. 12239 */ 12240 tag_str = g_strdup_printf ("----://%u/%s", 12241 table, (char *) node->data + offset); 12242 12243 /* memcpy To be sure we're preserving byte order */ 12244 memcpy (tag_str, entity, 4); 12245 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str); 12246 12247 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL); 12248 12249 g_free (tag_str); 12250 12251 return; 12252 12253 /* ERRORS */ 12254 short_read: 12255 { 12256 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification"); 12257 return; 12258 } 12259 } 12260 12261 static gboolean 12262 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist, 12263 const char *tag, const char *dummy, GNode * node) 12264 { 12265 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; 12266 GNode *data; 12267 char *s; 12268 int len; 12269 guint32 type; 12270 int offset; 12271 gboolean ret = TRUE; 12272 const gchar *charset = NULL; 12273 12274 data = qtdemux_tree_get_child_by_type (node, FOURCC_data); 12275 if (data) { 12276 len = QT_UINT32 (data->data); 12277 type = QT_UINT32 ((guint8 *) data->data + 8); 12278 if (type == 0x00000001 && len > 16) { 12279 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16, 12280 env_vars); 12281 if (s) { 12282 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s)); 12283 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL); 12284 g_free (s); 12285 } else { 12286 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag); 12287 } 12288 } 12289 } else { 12290 len = QT_UINT32 (node->data); 12291 type = QT_UINT32 ((guint8 *) node->data + 4); 12292 if ((type >> 24) == 0xa9 && len > 8 + 4) { 12293 gint str_len; 12294 gint lang_code; 12295 12296 /* Type starts with the (C) symbol, so the next data is a list 12297 * of (string size(16), language code(16), string) */ 12298 12299 str_len = QT_UINT16 ((guint8 *) node->data + 8); 12300 lang_code = QT_UINT16 ((guint8 *) node->data + 10); 12301 12302 /* the string + fourcc + size + 2 16bit fields, 12303 * means that there are more tags in this atom */ 12304 if (len > str_len + 8 + 4) { 12305 /* TODO how to represent the same tag in different languages? */ 12306 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple " 12307 "text alternatives, reading only first one"); 12308 } 12309 12310 offset = 12; 12311 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */ 12312 GST_DEBUG_OBJECT (qtdemux, "found international text tag"); 12313 12314 if (lang_code < 0x800) { /* MAC encoded string */ 12315 charset = "mac"; 12316 } 12317 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux, 12318 QT_FOURCC ((guint8 *) node->data + 4))) { 12319 guint32 type = QT_UINT32 ((guint8 *) node->data + 8); 12320 12321 /* we go for 3GP style encoding if major brands claims so, 12322 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */ 12323 if (qtdemux_is_brand_3gp (qtdemux, TRUE) || 12324 (qtdemux_is_brand_3gp (qtdemux, FALSE) && 12325 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) { 12326 offset = 14; 12327 /* 16-bit Language code is ignored here as well */ 12328 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag"); 12329 } else { 12330 goto normal; 12331 } 12332 } else { 12333 normal: 12334 offset = 8; 12335 GST_DEBUG_OBJECT (qtdemux, "found normal text tag"); 12336 ret = FALSE; /* may have to fallback */ 12337 } 12338 if (charset) { 12339 GError *err = NULL; 12340 12341 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8", 12342 charset, NULL, NULL, &err); 12343 if (err) { 12344 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:" 12345 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code, 12346 err->message); 12347 g_error_free (err); 12348 } 12349 } else { 12350 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset, 12351 len - offset, env_vars); 12352 } 12353 if (s) { 12354 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s)); 12355 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL); 12356 g_free (s); 12357 ret = TRUE; 12358 } else { 12359 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag); 12360 } 12361 } 12362 return ret; 12363 } 12364 12365 static void 12366 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist, 12367 const char *tag, const char *dummy, GNode * node) 12368 { 12369 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node); 12370 } 12371 12372 static void 12373 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist, 12374 const char *tag, const char *dummy, GNode * node) 12375 { 12376 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; 12377 guint8 *data; 12378 char *s, *t, *k = NULL; 12379 int len; 12380 int offset; 12381 int count; 12382 12383 /* first try normal string tag if major brand not 3GP */ 12384 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) { 12385 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) { 12386 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand; 12387 * let's try it 3gpp way after minor safety check */ 12388 data = node->data; 12389 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE)) 12390 return; 12391 } else 12392 return; 12393 } 12394 12395 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag"); 12396 12397 data = node->data; 12398 12399 len = QT_UINT32 (data); 12400 if (len < 15) 12401 goto short_read; 12402 12403 count = QT_UINT8 (data + 14); 12404 offset = 15; 12405 for (; count; count--) { 12406 gint slen; 12407 12408 if (offset + 1 > len) 12409 goto short_read; 12410 slen = QT_UINT8 (data + offset); 12411 offset += 1; 12412 if (offset + slen > len) 12413 goto short_read; 12414 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset, 12415 slen, env_vars); 12416 if (s) { 12417 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s)); 12418 if (k) { 12419 t = g_strjoin (",", k, s, NULL); 12420 g_free (s); 12421 g_free (k); 12422 k = t; 12423 } else { 12424 k = s; 12425 } 12426 } else { 12427 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8"); 12428 } 12429 offset += slen; 12430 } 12431 12432 done: 12433 if (k) { 12434 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k)); 12435 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL); 12436 } 12437 g_free (k); 12438 12439 return; 12440 12441 /* ERRORS */ 12442 short_read: 12443 { 12444 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords"); 12445 goto done; 12446 } 12447 } 12448 12449 static void 12450 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist, 12451 const char *tag1, const char *tag2, GNode * node) 12452 { 12453 GNode *data; 12454 int len; 12455 int type; 12456 int n1, n2; 12457 12458 data = qtdemux_tree_get_child_by_type (node, FOURCC_data); 12459 if (data) { 12460 len = QT_UINT32 (data->data); 12461 type = QT_UINT32 ((guint8 *) data->data + 8); 12462 if (type == 0x00000000 && len >= 22) { 12463 n1 = QT_UINT16 ((guint8 *) data->data + 18); 12464 n2 = QT_UINT16 ((guint8 *) data->data + 20); 12465 if (n1 > 0) { 12466 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1); 12467 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL); 12468 } 12469 if (n2 > 0) { 12470 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2); 12471 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL); 12472 } 12473 } 12474 } 12475 } 12476 12477 static void 12478 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist, 12479 const char *tag1, const char *dummy, GNode * node) 12480 { 12481 GNode *data; 12482 int len; 12483 int type; 12484 int n1; 12485 12486 data = qtdemux_tree_get_child_by_type (node, FOURCC_data); 12487 if (data) { 12488 len = QT_UINT32 (data->data); 12489 type = QT_UINT32 ((guint8 *) data->data + 8); 12490 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len); 12491 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */ 12492 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) { 12493 n1 = QT_UINT16 ((guint8 *) data->data + 16); 12494 if (n1) { 12495 /* do not add bpm=0 */ 12496 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1); 12497 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1, 12498 NULL); 12499 } 12500 } 12501 } 12502 } 12503 12504 static void 12505 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist, 12506 const char *tag1, const char *dummy, GNode * node) 12507 { 12508 GNode *data; 12509 int len; 12510 int type; 12511 guint32 num; 12512 12513 data = qtdemux_tree_get_child_by_type (node, FOURCC_data); 12514 if (data) { 12515 len = QT_UINT32 (data->data); 12516 type = QT_UINT32 ((guint8 *) data->data + 8); 12517 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len); 12518 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */ 12519 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) { 12520 num = QT_UINT32 ((guint8 *) data->data + 16); 12521 if (num) { 12522 /* do not add num=0 */ 12523 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num); 12524 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL); 12525 } 12526 } 12527 } 12528 } 12529 12530 static void 12531 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist, 12532 const char *tag1, const char *dummy, GNode * node) 12533 { 12534 GNode *data; 12535 int len; 12536 int type; 12537 GstSample *sample; 12538 12539 data = qtdemux_tree_get_child_by_type (node, FOURCC_data); 12540 if (data) { 12541 len = QT_UINT32 (data->data); 12542 type = QT_UINT32 ((guint8 *) data->data + 8); 12543 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len); 12544 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) { 12545 GstTagImageType image_type; 12546 12547 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0) 12548 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER; 12549 else 12550 image_type = GST_TAG_IMAGE_TYPE_NONE; 12551 12552 if ((sample = 12553 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16, 12554 len - 16, image_type))) { 12555 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16); 12556 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL); 12557 gst_sample_unref (sample); 12558 } 12559 } 12560 } 12561 } 12562 12563 static void 12564 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist, 12565 const char *tag, const char *dummy, GNode * node) 12566 { 12567 GNode *data; 12568 char *s; 12569 int len; 12570 int type; 12571 12572 data = qtdemux_tree_get_child_by_type (node, FOURCC_data); 12573 if (data) { 12574 len = QT_UINT32 (data->data); 12575 type = QT_UINT32 ((guint8 *) data->data + 8); 12576 if (type == 0x00000001 && len > 16) { 12577 guint y, m = 1, d = 1; 12578 gint ret; 12579 12580 s = g_strndup ((char *) data->data + 16, len - 16); 12581 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s); 12582 ret = sscanf (s, "%u-%u-%u", &y, &m, &d); 12583 if (ret >= 1 && y > 1500 && y < 3000) { 12584 GDate *date; 12585 12586 date = g_date_new_dmy (d, m, y); 12587 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL); 12588 g_date_free (date); 12589 } else { 12590 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s); 12591 } 12592 g_free (s); 12593 } 12594 } 12595 } 12596 12597 static void 12598 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist, 12599 const char *tag, const char *dummy, GNode * node) 12600 { 12601 GNode *data; 12602 12603 data = qtdemux_tree_get_child_by_type (node, FOURCC_data); 12604 12605 /* re-route to normal string tag if major brand says so 12606 * or no data atom and compatible brand suggests so */ 12607 if (qtdemux_is_brand_3gp (qtdemux, TRUE) || 12608 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) { 12609 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node); 12610 return; 12611 } 12612 12613 if (data) { 12614 guint len, type, n; 12615 12616 len = QT_UINT32 (data->data); 12617 type = QT_UINT32 ((guint8 *) data->data + 8); 12618 if (type == 0x00000000 && len >= 18) { 12619 n = QT_UINT16 ((guint8 *) data->data + 16); 12620 if (n > 0) { 12621 const gchar *genre; 12622 12623 genre = gst_tag_id3_genre_get (n - 1); 12624 if (genre != NULL) { 12625 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre); 12626 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL); 12627 } 12628 } 12629 } 12630 } 12631 } 12632 12633 static void 12634 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist, 12635 const gchar * tag, guint8 * data, guint32 datasize) 12636 { 12637 gdouble value; 12638 gchar *datacopy; 12639 12640 /* make a copy to have \0 at the end */ 12641 datacopy = g_strndup ((gchar *) data, datasize); 12642 12643 /* convert the str to double */ 12644 if (sscanf (datacopy, "%lf", &value) == 1) { 12645 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy); 12646 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL); 12647 } else { 12648 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s", 12649 datacopy); 12650 } 12651 g_free (datacopy); 12652 } 12653 12654 12655 static void 12656 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist, 12657 const char *tag, const char *tag_bis, GNode * node) 12658 { 12659 GNode *mean; 12660 GNode *name; 12661 GNode *data; 12662 guint32 meansize; 12663 guint32 namesize; 12664 guint32 datatype; 12665 guint32 datasize; 12666 const gchar *meanstr; 12667 const gchar *namestr; 12668 12669 /* checking the whole ---- atom size for consistency */ 12670 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) { 12671 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring"); 12672 return; 12673 } 12674 12675 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean); 12676 if (!mean) { 12677 GST_WARNING_OBJECT (demux, "No 'mean' atom found"); 12678 return; 12679 } 12680 12681 meansize = QT_UINT32 (mean->data); 12682 if (meansize <= 12) { 12683 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag"); 12684 return; 12685 } 12686 meanstr = ((gchar *) mean->data) + 12; 12687 meansize -= 12; 12688 12689 name = qtdemux_tree_get_child_by_type (node, FOURCC_name); 12690 if (!name) { 12691 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag"); 12692 return; 12693 } 12694 12695 namesize = QT_UINT32 (name->data); 12696 if (namesize <= 12) { 12697 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag"); 12698 return; 12699 } 12700 namestr = ((gchar *) name->data) + 12; 12701 namesize -= 12; 12702 12703 /* 12704 * Data atom is: 12705 * uint32 - size 12706 * uint32 - name 12707 * uint8 - version 12708 * uint24 - data type 12709 * uint32 - all 0 12710 * rest - the data 12711 */ 12712 data = qtdemux_tree_get_child_by_type (node, FOURCC_data); 12713 if (!data) { 12714 GST_WARNING_OBJECT (demux, "No data atom in this tag"); 12715 return; 12716 } 12717 datasize = QT_UINT32 (data->data); 12718 if (datasize <= 16) { 12719 GST_WARNING_OBJECT (demux, "Data atom too small"); 12720 return; 12721 } 12722 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF; 12723 12724 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) || 12725 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) { 12726 static const struct 12727 { 12728 const gchar name[28]; 12729 const gchar tag[28]; 12730 } tags[] = { 12731 { 12732 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, { 12733 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, { 12734 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, { 12735 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, { 12736 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, { 12737 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, { 12738 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, { 12739 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID} 12740 }; 12741 int i; 12742 12743 for (i = 0; i < G_N_ELEMENTS (tags); ++i) { 12744 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) { 12745 switch (gst_tag_get_type (tags[i].tag)) { 12746 case G_TYPE_DOUBLE: 12747 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag, 12748 ((guint8 *) data->data) + 16, datasize - 16); 12749 break; 12750 case G_TYPE_STRING: 12751 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node); 12752 break; 12753 default: 12754 /* not reached */ 12755 break; 12756 } 12757 break; 12758 } 12759 } 12760 if (i == G_N_ELEMENTS (tags)) 12761 goto unknown_tag; 12762 } else { 12763 goto unknown_tag; 12764 } 12765 12766 return; 12767 12768 /* errors */ 12769 unknown_tag: 12770 #ifndef GST_DISABLE_GST_DEBUG 12771 { 12772 gchar *namestr_dbg; 12773 gchar *meanstr_dbg; 12774 12775 meanstr_dbg = g_strndup (meanstr, meansize); 12776 namestr_dbg = g_strndup (namestr, namesize); 12777 12778 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, " 12779 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype); 12780 12781 g_free (namestr_dbg); 12782 g_free (meanstr_dbg); 12783 } 12784 #endif 12785 return; 12786 } 12787 12788 static void 12789 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag, 12790 const char *tag_bis, GNode * node) 12791 { 12792 guint8 *data; 12793 GstBuffer *buf; 12794 guint len; 12795 GstTagList *id32_taglist = NULL; 12796 12797 GST_LOG_OBJECT (demux, "parsing ID32"); 12798 12799 data = node->data; 12800 len = GST_READ_UINT32_BE (data); 12801 12802 /* need at least full box and language tag */ 12803 if (len < 12 + 2) 12804 return; 12805 12806 buf = gst_buffer_new_allocate (NULL, len - 14, NULL); 12807 gst_buffer_fill (buf, 0, data + 14, len - 14); 12808 12809 id32_taglist = gst_tag_list_from_id3v2_tag (buf); 12810 if (id32_taglist) { 12811 GST_LOG_OBJECT (demux, "parsing ok"); 12812 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP); 12813 gst_tag_list_unref (id32_taglist); 12814 } else { 12815 GST_LOG_OBJECT (demux, "parsing failed"); 12816 } 12817 12818 gst_buffer_unref (buf); 12819 } 12820 12821 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist, 12822 const char *tag, const char *tag_bis, GNode * node); 12823 12824 /* unmapped tags 12825 FOURCC_pcst -> if media is a podcast -> bool 12826 FOURCC_cpil -> if media is part of a compilation -> bool 12827 FOURCC_pgap -> if media is part of a gapless context -> bool 12828 FOURCC_tven -> the tv episode id e.g. S01E23 -> str 12829 */ 12830 12831 static const struct 12832 { 12833 guint32 fourcc; 12834 const gchar *gst_tag; 12835 const gchar *gst_tag_bis; 12836 const GstQTDemuxAddTagFunc func; 12837 } add_funcs[] = { 12838 { 12839 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, { 12840 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, { 12841 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, { 12842 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, { 12843 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { 12844 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, { 12845 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { 12846 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, { 12847 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, { 12848 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, { 12849 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, { 12850 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, { 12851 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, { 12852 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, { 12853 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, { 12854 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, { 12855 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, { 12856 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, { 12857 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, { 12858 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, { 12859 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, { 12860 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, { 12861 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, 12862 qtdemux_tag_add_num}, { 12863 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, 12864 qtdemux_tag_add_num}, { 12865 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, { 12866 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, { 12867 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, { 12868 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, { 12869 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, { 12870 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, { 12871 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, { 12872 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, { 12873 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, { 12874 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, { 12875 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, { 12876 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, { 12877 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, { 12878 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, { 12879 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, { 12880 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, { 12881 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, { 12882 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL, 12883 qtdemux_tag_add_classification}, { 12884 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, { 12885 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, { 12886 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, { 12887 12888 /* This is a special case, some tags are stored in this 12889 * 'reverse dns naming', according to: 12890 * http://atomicparsley.sourceforge.net/mpeg-4files.html and 12891 * bug #614471 12892 */ 12893 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, { 12894 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */ 12895 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32} 12896 }; 12897 12898 struct _GstQtDemuxTagList 12899 { 12900 GstQTDemux *demux; 12901 GstTagList *taglist; 12902 }; 12903 typedef struct _GstQtDemuxTagList GstQtDemuxTagList; 12904 12905 static void 12906 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist) 12907 { 12908 gint len; 12909 guint8 *data; 12910 GstBuffer *buf; 12911 gchar *media_type; 12912 const gchar *style; 12913 GstSample *sample; 12914 GstStructure *s; 12915 guint i; 12916 guint8 ndata[4]; 12917 GstQTDemux *demux = qtdemuxtaglist->demux; 12918 GstTagList *taglist = qtdemuxtaglist->taglist; 12919 12920 data = node->data; 12921 len = QT_UINT32 (data); 12922 buf = gst_buffer_new_and_alloc (len); 12923 gst_buffer_fill (buf, 0, data, len); 12924 12925 /* heuristic to determine style of tag */ 12926 if (QT_FOURCC (data + 4) == FOURCC_____ || 12927 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data)) 12928 style = "itunes"; 12929 else if (demux->major_brand == FOURCC_qt__) 12930 style = "quicktime"; 12931 /* fall back to assuming iso/3gp tag style */ 12932 else 12933 style = "iso"; 12934 12935 /* santize the name for the caps. */ 12936 for (i = 0; i < 4; i++) { 12937 guint8 d = data[4 + i]; 12938 if (g_ascii_isalnum (d)) 12939 ndata[i] = g_ascii_tolower (d); 12940 else 12941 ndata[i] = '_'; 12942 } 12943 12944 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag", 12945 ndata[0], ndata[1], ndata[2], ndata[3]); 12946 GST_DEBUG_OBJECT (demux, "media type %s", media_type); 12947 12948 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL); 12949 sample = gst_sample_new (buf, NULL, NULL, s); 12950 gst_buffer_unref (buf); 12951 g_free (media_type); 12952 12953 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT, 12954 len, s); 12955 12956 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, 12957 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL); 12958 12959 gst_sample_unref (sample); 12960 } 12961 12962 static void 12963 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta) 12964 { 12965 GNode *meta; 12966 GNode *ilst; 12967 GNode *xmp_; 12968 GNode *node; 12969 gint i; 12970 GstQtDemuxTagList demuxtaglist; 12971 12972 demuxtaglist.demux = qtdemux; 12973 demuxtaglist.taglist = taglist; 12974 12975 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta); 12976 if (meta != NULL) { 12977 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst); 12978 if (ilst == NULL) { 12979 GST_LOG_OBJECT (qtdemux, "no ilst"); 12980 return; 12981 } 12982 } else { 12983 ilst = udta; 12984 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself"); 12985 } 12986 12987 i = 0; 12988 while (i < G_N_ELEMENTS (add_funcs)) { 12989 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc); 12990 if (node) { 12991 gint len; 12992 12993 len = QT_UINT32 (node->data); 12994 if (len < 12) { 12995 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT, 12996 GST_FOURCC_ARGS (add_funcs[i].fourcc)); 12997 } else { 12998 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag, 12999 add_funcs[i].gst_tag_bis, node); 13000 } 13001 g_node_destroy (node); 13002 } else { 13003 i++; 13004 } 13005 } 13006 13007 /* parsed nodes have been removed, pass along remainder as blob */ 13008 g_node_children_foreach (ilst, G_TRAVERSE_ALL, 13009 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist); 13010 13011 #ifndef GSTREAMER_LITE 13012 /* parse up XMP_ node if existing */ 13013 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_); 13014 if (xmp_ != NULL) { 13015 GstBuffer *buf; 13016 GstTagList *xmptaglist; 13017 13018 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8, 13019 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL); 13020 xmptaglist = gst_tag_list_from_xmp_buffer (buf); 13021 gst_buffer_unref (buf); 13022 13023 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist); 13024 } else { 13025 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found"); 13026 } 13027 #endif // GSTREAMER_LITE 13028 } 13029 13030 typedef struct 13031 { 13032 GstStructure *structure; /* helper for sort function */ 13033 gchar *location; 13034 guint min_req_bitrate; 13035 guint min_req_qt_version; 13036 } GstQtReference; 13037 13038 static gint 13039 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b) 13040 { 13041 GstQtReference *ref_a = (GstQtReference *) a; 13042 GstQtReference *ref_b = (GstQtReference *) b; 13043 13044 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version) 13045 return ref_b->min_req_qt_version - ref_a->min_req_qt_version; 13046 13047 /* known bitrates go before unknown; higher bitrates go first */ 13048 return ref_b->min_req_bitrate - ref_a->min_req_bitrate; 13049 } 13050 13051 /* sort the redirects and post a message for the application. 13052 */ 13053 static void 13054 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references) 13055 { 13056 GstQtReference *best; 13057 GstStructure *s; 13058 GstMessage *msg; 13059 GValue list_val = { 0, }; 13060 GList *l; 13061 13062 g_assert (references != NULL); 13063 13064 references = g_list_sort (references, qtdemux_redirects_sort_func); 13065 13066 best = (GstQtReference *) references->data; 13067 13068 g_value_init (&list_val, GST_TYPE_LIST); 13069 13070 for (l = references; l != NULL; l = l->next) { 13071 GstQtReference *ref = (GstQtReference *) l->data; 13072 GValue struct_val = { 0, }; 13073 13074 ref->structure = gst_structure_new ("redirect", 13075 "new-location", G_TYPE_STRING, ref->location, NULL); 13076 13077 if (ref->min_req_bitrate > 0) { 13078 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT, 13079 ref->min_req_bitrate, NULL); 13080 } 13081 13082 g_value_init (&struct_val, GST_TYPE_STRUCTURE); 13083 g_value_set_boxed (&struct_val, ref->structure); 13084 gst_value_list_append_value (&list_val, &struct_val); 13085 g_value_unset (&struct_val); 13086 /* don't free anything here yet, since we need best->structure below */ 13087 } 13088 13089 g_assert (best != NULL); 13090 s = gst_structure_copy (best->structure); 13091 13092 if (g_list_length (references) > 1) { 13093 gst_structure_set_value (s, "locations", &list_val); 13094 } 13095 13096 g_value_unset (&list_val); 13097 13098 for (l = references; l != NULL; l = l->next) { 13099 GstQtReference *ref = (GstQtReference *) l->data; 13100 13101 gst_structure_free (ref->structure); 13102 g_free (ref->location); 13103 g_free (ref); 13104 } 13105 g_list_free (references); 13106 13107 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s); 13108 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s); 13109 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg); 13110 qtdemux->posted_redirect = TRUE; 13111 } 13112 13113 /* look for redirect nodes, collect all redirect information and 13114 * process it. 13115 */ 13116 static gboolean 13117 qtdemux_parse_redirects (GstQTDemux * qtdemux) 13118 { 13119 GNode *rmra, *rmda, *rdrf; 13120 13121 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra); 13122 if (rmra) { 13123 GList *redirects = NULL; 13124 13125 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda); 13126 while (rmda) { 13127 GstQtReference ref = { NULL, NULL, 0, 0 }; 13128 GNode *rmdr, *rmvc; 13129 13130 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) { 13131 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12); 13132 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u", 13133 ref.min_req_bitrate); 13134 } 13135 13136 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) { 13137 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12); 13138 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16); 13139 13140 #ifndef GST_DISABLE_GST_DEBUG 13141 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20); 13142 #endif 13143 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24); 13144 13145 GST_LOG_OBJECT (qtdemux, 13146 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x" 13147 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version, 13148 bitmask, check_type); 13149 if (package == FOURCC_qtim && check_type == 0) { 13150 ref.min_req_qt_version = version; 13151 } 13152 } 13153 13154 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf); 13155 if (rdrf) { 13156 guint32 ref_type; 13157 guint8 *ref_data; 13158 guint ref_len; 13159 13160 ref_len = QT_UINT32 ((guint8 *) rdrf->data); 13161 if (ref_len > 20) { 13162 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12); 13163 ref_data = (guint8 *) rdrf->data + 20; 13164 if (ref_type == FOURCC_alis) { 13165 guint record_len, record_version, fn_len; 13166 13167 if (ref_len > 70) { 13168 /* MacOSX alias record, google for alias-layout.txt */ 13169 record_len = QT_UINT16 (ref_data + 4); 13170 record_version = QT_UINT16 (ref_data + 4 + 2); 13171 fn_len = QT_UINT8 (ref_data + 50); 13172 if (record_len > 50 && record_version == 2 && fn_len > 0) { 13173 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len); 13174 } 13175 } else { 13176 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)", 13177 ref_len); 13178 } 13179 } else if (ref_type == FOURCC_url_) { 13180 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8); 13181 } else { 13182 GST_DEBUG_OBJECT (qtdemux, 13183 "unknown rdrf reference type %" GST_FOURCC_FORMAT, 13184 GST_FOURCC_ARGS (ref_type)); 13185 } 13186 if (ref.location != NULL) { 13187 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location); 13188 redirects = 13189 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref))); 13190 } else { 13191 GST_WARNING_OBJECT (qtdemux, 13192 "Failed to extract redirect location from rdrf atom"); 13193 } 13194 } else { 13195 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len); 13196 } 13197 } 13198 13199 /* look for others */ 13200 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda); 13201 } 13202 13203 if (redirects != NULL) { 13204 qtdemux_process_redirects (qtdemux, redirects); 13205 } 13206 } 13207 return TRUE; 13208 } 13209 13210 static GstTagList * 13211 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags) 13212 { 13213 const gchar *fmt; 13214 13215 if (tags == NULL) { 13216 tags = gst_tag_list_new_empty (); 13217 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL); 13218 } 13219 13220 if (qtdemux->major_brand == FOURCC_mjp2) 13221 fmt = "Motion JPEG 2000"; 13222 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__) 13223 fmt = "3GP"; 13224 else if (qtdemux->major_brand == FOURCC_qt__) 13225 fmt = "Quicktime"; 13226 else if (qtdemux->fragmented) 13227 fmt = "ISO fMP4"; 13228 else 13229 fmt = "ISO MP4/M4A"; 13230 13231 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'", 13232 GST_FOURCC_ARGS (qtdemux->major_brand), fmt); 13233 13234 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT, 13235 fmt, NULL); 13236 13237 return tags; 13238 } 13239 13240 /* we have read the complete moov node now. 13241 * This function parses all of the relevant info, creates the traks and 13242 * prepares all data structures for playback 13243 */ 13244 static gboolean 13245 qtdemux_parse_tree (GstQTDemux * qtdemux) 13246 { 13247 GNode *mvhd; 13248 GNode *trak; 13249 GNode *udta; 13250 GNode *mvex; 13251 GstClockTime duration; 13252 GNode *pssh; 13253 guint64 creation_time; 13254 GstDateTime *datetime = NULL; 13255 gint version; 13256 13257 /* make sure we have a usable taglist */ 13258 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list); 13259 13260 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd); 13261 if (mvhd == NULL) { 13262 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects."); 13263 return qtdemux_parse_redirects (qtdemux); 13264 } 13265 13266 version = QT_UINT8 ((guint8 *) mvhd->data + 8); 13267 if (version == 1) { 13268 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12); 13269 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28); 13270 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32); 13271 } else if (version == 0) { 13272 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12); 13273 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20); 13274 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24); 13275 } else { 13276 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version); 13277 return FALSE; 13278 } 13279 13280 /* Moving qt creation time (secs since 1904) to unix time */ 13281 if (creation_time != 0) { 13282 /* Try to use epoch first as it should be faster and more commonly found */ 13283 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) { 13284 GTimeVal now; 13285 13286 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970; 13287 /* some data cleansing sanity */ 13288 g_get_current_time (&now); 13289 if (now.tv_sec + 24 * 3600 < creation_time) { 13290 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time"); 13291 } else { 13292 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time); 13293 } 13294 } else { 13295 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0); 13296 GDateTime *dt, *dt_local; 13297 13298 dt = g_date_time_add_seconds (base_dt, creation_time); 13299 dt_local = g_date_time_to_local (dt); 13300 datetime = gst_date_time_new_from_g_date_time (dt_local); 13301 13302 g_date_time_unref (base_dt); 13303 g_date_time_unref (dt); 13304 } 13305 } 13306 if (datetime) { 13307 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */ 13308 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME, 13309 datetime, NULL); 13310 gst_date_time_unref (datetime); 13311 } 13312 13313 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale); 13314 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration); 13315 13316 /* check for fragmented file and get some (default) data */ 13317 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex); 13318 if (mvex) { 13319 GNode *mehd; 13320 GstByteReader mehd_data; 13321 13322 /* let track parsing or anyone know weird stuff might happen ... */ 13323 qtdemux->fragmented = TRUE; 13324 13325 /* compensate for total duration */ 13326 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data); 13327 if (mehd) 13328 qtdemux_parse_mehd (qtdemux, &mehd_data); 13329 } 13330 13331 /* set duration in the segment info */ 13332 gst_qtdemux_get_duration (qtdemux, &duration); 13333 if (duration) { 13334 qtdemux->segment.duration = duration; 13335 /* also do not exceed duration; stop is set that way post seek anyway, 13336 * and segment activation falls back to duration, 13337 * whereas loop only checks stop, so let's align this here as well */ 13338 qtdemux->segment.stop = duration; 13339 } 13340 13341 /* parse all traks */ 13342 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak); 13343 while (trak) { 13344 #ifdef GSTREAMER_LITE 13345 if (!qtdemux_parse_trak (qtdemux, trak)) 13346 return FALSE; 13347 #else 13348 qtdemux_parse_trak (qtdemux, trak); 13349 #endif // GSTREAMER_LITE 13350 /* iterate all siblings */ 13351 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak); 13352 } 13353 13354 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list); 13355 13356 /* find tags */ 13357 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta); 13358 if (udta) { 13359 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta); 13360 } else { 13361 GST_LOG_OBJECT (qtdemux, "No udta node found."); 13362 } 13363 13364 /* maybe also some tags in meta box */ 13365 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta); 13366 if (udta) { 13367 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags."); 13368 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta); 13369 } else { 13370 GST_LOG_OBJECT (qtdemux, "No meta node found."); 13371 } 13372 13373 /* parse any protection system info */ 13374 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh); 13375 while (pssh) { 13376 GST_LOG_OBJECT (qtdemux, "Parsing pssh box."); 13377 qtdemux_parse_pssh (qtdemux, pssh); 13378 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh); 13379 } 13380 13381 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list); 13382 13383 return TRUE; 13384 } 13385 13386 /* taken from ffmpeg */ 13387 static int 13388 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out) 13389 { 13390 int count = 4; 13391 int len = 0; 13392 13393 while (count--) { 13394 int c; 13395 13396 if (ptr >= end) 13397 return -1; 13398 13399 c = *ptr++; 13400 len = (len << 7) | (c & 0x7f); 13401 if (!(c & 0x80)) 13402 break; 13403 } 13404 *end_out = ptr; 13405 return len; 13406 } 13407 13408 /* this can change the codec originally present in @list */ 13409 #ifdef GSTREAMER_LITE 13410 static gboolean 13411 #else 13412 static void 13413 #endif // GSTREAMER_LITE 13414 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream, 13415 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list) 13416 { 13417 int len = QT_UINT32 (esds->data); 13418 guint8 *ptr = esds->data; 13419 guint8 *end = ptr + len; 13420 int tag; 13421 guint8 *data_ptr = NULL; 13422 int data_len = 0; 13423 guint8 object_type_id = 0; 13424 const char *codec_name = NULL; 13425 GstCaps *caps = NULL; 13426 13427 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len); 13428 ptr += 8; 13429 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr)); 13430 ptr += 4; 13431 while (ptr + 1 < end) { 13432 tag = QT_UINT8 (ptr); 13433 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag); 13434 ptr++; 13435 len = read_descr_size (ptr, end, &ptr); 13436 GST_DEBUG_OBJECT (qtdemux, "len = %d", len); 13437 13438 /* Check the stated amount of data is available for reading */ 13439 if (len < 0 || ptr + len > end) 13440 break; 13441 13442 switch (tag) { 13443 case ES_DESCRIPTOR_TAG: 13444 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr)); 13445 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2)); 13446 ptr += 3; 13447 break; 13448 case DECODER_CONFIG_DESC_TAG:{ 13449 guint max_bitrate, avg_bitrate; 13450 13451 object_type_id = QT_UINT8 (ptr); 13452 max_bitrate = QT_UINT32 (ptr + 5); 13453 avg_bitrate = QT_UINT32 (ptr + 9); 13454 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id); 13455 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1)); 13456 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2)); 13457 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate); 13458 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate); 13459 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) { 13460 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, 13461 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL); 13462 } 13463 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) { 13464 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, 13465 avg_bitrate, NULL); 13466 } 13467 ptr += 13; 13468 break; 13469 } 13470 case DECODER_SPECIFIC_INFO_TAG: 13471 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len); 13472 #ifdef GSTREAMER_LITE 13473 if (end - len < ptr) 13474 return FALSE; 13475 #endif // GSTREAMER_LITE 13476 if (object_type_id == 0xe0 && len == 0x40) { 13477 guint8 *data; 13478 GstStructure *s; 13479 guint32 clut[16]; 13480 gint i; 13481 13482 GST_DEBUG_OBJECT (qtdemux, 13483 "Have VOBSUB palette. Creating palette event"); 13484 /* move to decConfigDescr data and read palette */ 13485 data = ptr; 13486 for (i = 0; i < 16; i++) { 13487 clut[i] = QT_UINT32 (data); 13488 data += 4; 13489 } 13490 13491 s = gst_structure_new ("application/x-gst-dvd", "event", 13492 G_TYPE_STRING, "dvd-spu-clut-change", 13493 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1], 13494 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3], 13495 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5], 13496 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7], 13497 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9], 13498 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11], 13499 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13], 13500 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15], 13501 NULL); 13502 13503 /* store event and trigger custom processing */ 13504 stream->pending_event = 13505 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s); 13506 } else { 13507 /* Generic codec_data handler puts it on the caps */ 13508 data_ptr = ptr; 13509 data_len = len; 13510 } 13511 13512 ptr += len; 13513 break; 13514 case SL_CONFIG_DESC_TAG: 13515 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr)); 13516 ptr += 1; 13517 break; 13518 default: 13519 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x", 13520 tag); 13521 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len); 13522 ptr += len; 13523 break; 13524 } 13525 } 13526 13527 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is 13528 * in use, and should also be used to override some other parameters for some 13529 * codecs. */ 13530 switch (object_type_id) { 13531 case 0x20: /* MPEG-4 */ 13532 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the 13533 * profile_and_level_indication */ 13534 if (data_ptr != NULL && data_len >= 5 && 13535 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) { 13536 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps, 13537 data_ptr + 4, data_len - 4); 13538 } 13539 break; /* Nothing special needed here */ 13540 case 0x21: /* H.264 */ 13541 codec_name = "H.264 / AVC"; 13542 caps = gst_caps_new_simple ("video/x-h264", 13543 "stream-format", G_TYPE_STRING, "avc", 13544 "alignment", G_TYPE_STRING, "au", NULL); 13545 break; 13546 case 0x40: /* AAC (any) */ 13547 case 0x66: /* AAC Main */ 13548 case 0x67: /* AAC LC */ 13549 case 0x68: /* AAC SSR */ 13550 /* Override channels and rate based on the codec_data, as it's often 13551 * wrong. */ 13552 /* Only do so for basic setup without HE-AAC extension */ 13553 if (data_ptr && data_len == 2) { 13554 guint channels, rate; 13555 13556 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len); 13557 if (channels > 0) 13558 entry->n_channels = channels; 13559 13560 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len); 13561 if (rate > 0) 13562 entry->rate = rate; 13563 } 13564 13565 /* Set level and profile if possible */ 13566 if (data_ptr != NULL && data_len >= 2) { 13567 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps, 13568 data_ptr, data_len); 13569 } else { 13570 const gchar *profile_str = NULL; 13571 GstBuffer *buffer; 13572 GstMapInfo map; 13573 guint8 *codec_data; 13574 gint rate_idx, profile; 13575 13576 /* No codec_data, let's invent something. 13577 * FIXME: This is wrong for SBR! */ 13578 13579 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available"); 13580 13581 buffer = gst_buffer_new_and_alloc (2); 13582 gst_buffer_map (buffer, &map, GST_MAP_WRITE); 13583 codec_data = map.data; 13584 13585 rate_idx = 13586 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM 13587 (stream)->rate); 13588 13589 switch (object_type_id) { 13590 case 0x66: 13591 profile_str = "main"; 13592 profile = 0; 13593 break; 13594 case 0x67: 13595 profile_str = "lc"; 13596 profile = 1; 13597 break; 13598 case 0x68: 13599 profile_str = "ssr"; 13600 profile = 2; 13601 break; 13602 default: 13603 profile = 3; 13604 break; 13605 } 13606 13607 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1); 13608 codec_data[1] = 13609 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3); 13610 13611 gst_buffer_unmap (buffer, &map); 13612 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data", 13613 GST_TYPE_BUFFER, buffer, NULL); 13614 gst_buffer_unref (buffer); 13615 13616 if (profile_str) { 13617 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile", 13618 G_TYPE_STRING, profile_str, NULL); 13619 } 13620 } 13621 break; 13622 case 0x60: /* MPEG-2, various profiles */ 13623 case 0x61: 13624 case 0x62: 13625 case 0x63: 13626 case 0x64: 13627 case 0x65: 13628 codec_name = "MPEG-2 video"; 13629 caps = gst_caps_new_simple ("video/mpeg", 13630 "mpegversion", G_TYPE_INT, 2, 13631 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); 13632 break; 13633 case 0x69: /* MPEG-2 BC audio */ 13634 case 0x6B: /* MPEG-1 audio */ 13635 caps = gst_caps_new_simple ("audio/mpeg", 13636 "mpegversion", G_TYPE_INT, 1, NULL); 13637 codec_name = "MPEG-1 audio"; 13638 break; 13639 case 0x6A: /* MPEG-1 */ 13640 codec_name = "MPEG-1 video"; 13641 caps = gst_caps_new_simple ("video/mpeg", 13642 "mpegversion", G_TYPE_INT, 1, 13643 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); 13644 break; 13645 case 0x6C: /* MJPEG */ 13646 caps = 13647 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE, 13648 NULL); 13649 codec_name = "Motion-JPEG"; 13650 break; 13651 case 0x6D: /* PNG */ 13652 caps = 13653 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE, 13654 NULL); 13655 codec_name = "PNG still images"; 13656 break; 13657 case 0x6E: /* JPEG2000 */ 13658 codec_name = "JPEG-2000"; 13659 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL); 13660 break; 13661 case 0xA4: /* Dirac */ 13662 codec_name = "Dirac"; 13663 caps = gst_caps_new_empty_simple ("video/x-dirac"); 13664 break; 13665 case 0xA5: /* AC3 */ 13666 codec_name = "AC-3 audio"; 13667 caps = gst_caps_new_simple ("audio/x-ac3", 13668 "framed", G_TYPE_BOOLEAN, TRUE, NULL); 13669 break; 13670 case 0xA9: /* AC3 */ 13671 codec_name = "DTS audio"; 13672 caps = gst_caps_new_simple ("audio/x-dts", 13673 "framed", G_TYPE_BOOLEAN, TRUE, NULL); 13674 break; 13675 case 0xE1: /* QCELP */ 13676 /* QCELP, the codec_data is a riff tag (little endian) with 13677 * 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). */ 13678 caps = gst_caps_new_empty_simple ("audio/qcelp"); 13679 codec_name = "QCELP"; 13680 break; 13681 default: 13682 break; 13683 } 13684 13685 /* If we have a replacement caps, then change our caps for this stream */ 13686 if (caps) { 13687 gst_caps_unref (entry->caps); 13688 entry->caps = caps; 13689 } 13690 13691 if (codec_name && list) 13692 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, 13693 GST_TAG_AUDIO_CODEC, codec_name, NULL); 13694 13695 /* Add the codec_data attribute to caps, if we have it */ 13696 if (data_ptr) { 13697 GstBuffer *buffer; 13698 13699 buffer = gst_buffer_new_and_alloc (data_len); 13700 gst_buffer_fill (buffer, 0, data_ptr, data_len); 13701 13702 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds"); 13703 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len); 13704 13705 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER, 13706 buffer, NULL); 13707 gst_buffer_unref (buffer); 13708 13709 #if defined(GSTREAMER_LITE) && defined(OSX) 13710 switch (object_type_id) { 13711 case 0x40: /* AAC (any) */ 13712 case 0x66: /* AAC Main */ 13713 case 0x67: /* AAC LC */ 13714 case 0x68: /* AAC SSR */ 13715 { 13716 GstMapInfo info; 13717 int esds_len = QT_UINT32 (esds->data); 13718 GstBuffer* esds_buffer = gst_buffer_new_allocate (NULL, esds_len, NULL); 13719 if (esds_buffer) 13720 { 13721 if (gst_buffer_map(esds_buffer, &info, GST_MAP_WRITE)) 13722 { 13723 memcpy (info.data, esds->data, esds_len); 13724 gst_buffer_unmap(esds_buffer, &info); 13725 13726 GST_DEBUG_OBJECT (qtdemux, "setting esds_data from esds"); 13727 GST_MEMDUMP_OBJECT (qtdemux, "esds_data from esds", esds->data, esds_len); 13728 13729 gst_caps_set_simple (entry->caps, "esds_data", GST_TYPE_BUFFER, 13730 esds_buffer, NULL); 13731 } 13732 13733 gst_buffer_unref (esds_buffer); 13734 } 13735 } 13736 break; 13737 default: 13738 break; 13739 } 13740 #endif 13741 13742 } 13743 13744 #ifdef GSTREAMER_LITE 13745 return TRUE; 13746 #endif 13747 } 13748 13749 static inline GstCaps * 13750 _get_unknown_codec_name (const gchar * type, guint32 fourcc) 13751 { 13752 GstCaps *caps; 13753 guint i; 13754 char *s, fourstr[5]; 13755 13756 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc)); 13757 for (i = 0; i < 4; i++) { 13758 if (!g_ascii_isalnum (fourstr[i])) 13759 fourstr[i] = '_'; 13760 } 13761 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr)); 13762 caps = gst_caps_new_empty_simple (s); 13763 g_free (s); 13764 return caps; 13765 } 13766 13767 #define _codec(name) \ 13768 do { \ 13769 if (codec_name) { \ 13770 *codec_name = g_strdup (name); \ 13771 } \ 13772 } while (0) 13773 13774 static GstCaps * 13775 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, 13776 QtDemuxStreamStsdEntry * entry, guint32 fourcc, 13777 const guint8 * stsd_entry_data, gchar ** codec_name) 13778 { 13779 GstCaps *caps = NULL; 13780 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; 13781 13782 switch (fourcc) { 13783 case FOURCC_png: 13784 _codec ("PNG still images"); 13785 caps = gst_caps_new_empty_simple ("image/png"); 13786 break; 13787 case FOURCC_jpeg: 13788 _codec ("JPEG still images"); 13789 caps = 13790 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE, 13791 NULL); 13792 break; 13793 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'): 13794 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'): 13795 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'): 13796 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'): 13797 _codec ("Motion-JPEG"); 13798 caps = 13799 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE, 13800 NULL); 13801 break; 13802 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'): 13803 _codec ("Motion-JPEG format B"); 13804 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b"); 13805 break; 13806 case FOURCC_mjp2: 13807 _codec ("JPEG-2000"); 13808 /* override to what it should be according to spec, avoid palette_data */ 13809 entry->bits_per_sample = 24; 13810 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL); 13811 break; 13812 case FOURCC_SVQ3: 13813 _codec ("Sorensen video v.3"); 13814 caps = gst_caps_new_simple ("video/x-svq", 13815 "svqversion", G_TYPE_INT, 3, NULL); 13816 break; 13817 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'): 13818 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'): 13819 _codec ("Sorensen video v.1"); 13820 caps = gst_caps_new_simple ("video/x-svq", 13821 "svqversion", G_TYPE_INT, 1, NULL); 13822 break; 13823 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'): 13824 caps = gst_caps_new_empty_simple ("video/x-raw"); 13825 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL); 13826 _codec ("Windows Raw RGB"); 13827 stream->alignment = 32; 13828 break; 13829 case FOURCC_raw_: 13830 { 13831 guint16 bps; 13832 13833 bps = QT_UINT16 (stsd_entry_data + 82); 13834 switch (bps) { 13835 case 15: 13836 format = GST_VIDEO_FORMAT_RGB15; 13837 break; 13838 case 16: 13839 format = GST_VIDEO_FORMAT_RGB16; 13840 break; 13841 case 24: 13842 format = GST_VIDEO_FORMAT_RGB; 13843 break; 13844 case 32: 13845 format = GST_VIDEO_FORMAT_ARGB; 13846 break; 13847 default: 13848 /* unknown */ 13849 break; 13850 } 13851 break; 13852 } 13853 case GST_MAKE_FOURCC ('y', 'v', '1', '2'): 13854 format = GST_VIDEO_FORMAT_I420; 13855 break; 13856 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'): 13857 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'): 13858 format = GST_VIDEO_FORMAT_I420; 13859 break; 13860 case FOURCC_2vuy: 13861 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'): 13862 format = GST_VIDEO_FORMAT_UYVY; 13863 break; 13864 case GST_MAKE_FOURCC ('v', '3', '0', '8'): 13865 format = GST_VIDEO_FORMAT_v308; 13866 break; 13867 case GST_MAKE_FOURCC ('v', '2', '1', '6'): 13868 format = GST_VIDEO_FORMAT_v216; 13869 break; 13870 case FOURCC_v210: 13871 format = GST_VIDEO_FORMAT_v210; 13872 break; 13873 case GST_MAKE_FOURCC ('r', '2', '1', '0'): 13874 format = GST_VIDEO_FORMAT_r210; 13875 break; 13876 /* Packed YUV 4:4:4 10 bit in 32 bits, complex 13877 case GST_MAKE_FOURCC ('v', '4', '1', '0'): 13878 format = GST_VIDEO_FORMAT_v410; 13879 break; 13880 */ 13881 /* Packed YUV 4:4:4:4 8 bit in 32 bits 13882 * but different order than AYUV 13883 case GST_MAKE_FOURCC ('v', '4', '0', '8'): 13884 format = GST_VIDEO_FORMAT_v408; 13885 break; 13886 */ 13887 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'): 13888 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'): 13889 _codec ("MPEG-1 video"); 13890 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1, 13891 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); 13892 break; 13893 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */ 13894 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */ 13895 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */ 13896 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */ 13897 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */ 13898 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */ 13899 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */ 13900 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */ 13901 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */ 13902 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */ 13903 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */ 13904 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */ 13905 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */ 13906 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */ 13907 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */ 13908 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */ 13909 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */ 13910 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */ 13911 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */ 13912 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */ 13913 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */ 13914 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */ 13915 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */ 13916 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */ 13917 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */ 13918 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */ 13919 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */ 13920 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */ 13921 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */ 13922 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */ 13923 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */ 13924 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */ 13925 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */ 13926 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */ 13927 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */ 13928 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */ 13929 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */ 13930 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */ 13931 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */ 13932 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */ 13933 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */ 13934 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */ 13935 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */ 13936 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */ 13937 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */ 13938 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */ 13939 case GST_MAKE_FOURCC ('m', '2', 'v', '1'): 13940 _codec ("MPEG-2 video"); 13941 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2, 13942 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); 13943 break; 13944 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '): 13945 _codec ("GIF still images"); 13946 caps = gst_caps_new_empty_simple ("image/gif"); 13947 break; 13948 case FOURCC_h263: 13949 case GST_MAKE_FOURCC ('H', '2', '6', '3'): 13950 case FOURCC_s263: 13951 case GST_MAKE_FOURCC ('U', '2', '6', '3'): 13952 _codec ("H.263"); 13953 /* ffmpeg uses the height/width props, don't know why */ 13954 caps = gst_caps_new_simple ("video/x-h263", 13955 "variant", G_TYPE_STRING, "itu", NULL); 13956 break; 13957 case FOURCC_mp4v: 13958 case FOURCC_MP4V: 13959 _codec ("MPEG-4 video"); 13960 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4, 13961 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); 13962 break; 13963 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'): 13964 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'): 13965 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */ 13966 caps = gst_caps_new_simple ("video/x-msmpeg", 13967 "msmpegversion", G_TYPE_INT, 43, NULL); 13968 break; 13969 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'): 13970 _codec ("DivX 3"); 13971 caps = gst_caps_new_simple ("video/x-divx", 13972 "divxversion", G_TYPE_INT, 3, NULL); 13973 break; 13974 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'): 13975 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'): 13976 _codec ("DivX 4"); 13977 caps = gst_caps_new_simple ("video/x-divx", 13978 "divxversion", G_TYPE_INT, 4, NULL); 13979 break; 13980 case GST_MAKE_FOURCC ('D', 'X', '5', '0'): 13981 _codec ("DivX 5"); 13982 caps = gst_caps_new_simple ("video/x-divx", 13983 "divxversion", G_TYPE_INT, 5, NULL); 13984 break; 13985 13986 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'): 13987 _codec ("FFV1"); 13988 caps = gst_caps_new_simple ("video/x-ffv", 13989 "ffvversion", G_TYPE_INT, 1, NULL); 13990 break; 13991 13992 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'): 13993 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'): 13994 case FOURCC_XVID: 13995 case FOURCC_xvid: 13996 case FOURCC_FMP4: 13997 case FOURCC_fmp4: 13998 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'): 13999 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4, 14000 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); 14001 _codec ("MPEG-4"); 14002 break; 14003 14004 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'): 14005 _codec ("Cinepak"); 14006 caps = gst_caps_new_empty_simple ("video/x-cinepak"); 14007 break; 14008 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'): 14009 _codec ("Apple QuickDraw"); 14010 caps = gst_caps_new_empty_simple ("video/x-qdrw"); 14011 break; 14012 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'): 14013 _codec ("Apple video"); 14014 caps = gst_caps_new_empty_simple ("video/x-apple-video"); 14015 break; 14016 case FOURCC_H264: 14017 case FOURCC_avc1: 14018 _codec ("H.264 / AVC"); 14019 caps = gst_caps_new_simple ("video/x-h264", 14020 "stream-format", G_TYPE_STRING, "avc", 14021 "alignment", G_TYPE_STRING, "au", NULL); 14022 break; 14023 case FOURCC_avc3: 14024 _codec ("H.264 / AVC"); 14025 caps = gst_caps_new_simple ("video/x-h264", 14026 "stream-format", G_TYPE_STRING, "avc3", 14027 "alignment", G_TYPE_STRING, "au", NULL); 14028 break; 14029 case FOURCC_H265: 14030 case FOURCC_hvc1: 14031 _codec ("H.265 / HEVC"); 14032 caps = gst_caps_new_simple ("video/x-h265", 14033 "stream-format", G_TYPE_STRING, "hvc1", 14034 "alignment", G_TYPE_STRING, "au", NULL); 14035 break; 14036 case FOURCC_hev1: 14037 _codec ("H.265 / HEVC"); 14038 caps = gst_caps_new_simple ("video/x-h265", 14039 "stream-format", G_TYPE_STRING, "hev1", 14040 "alignment", G_TYPE_STRING, "au", NULL); 14041 break; 14042 case FOURCC_rle_: 14043 _codec ("Run-length encoding"); 14044 caps = gst_caps_new_simple ("video/x-rle", 14045 "layout", G_TYPE_STRING, "quicktime", NULL); 14046 break; 14047 case FOURCC_WRLE: 14048 _codec ("Run-length encoding"); 14049 caps = gst_caps_new_simple ("video/x-rle", 14050 "layout", G_TYPE_STRING, "microsoft", NULL); 14051 break; 14052 case GST_MAKE_FOURCC ('I', 'V', '3', '2'): 14053 case GST_MAKE_FOURCC ('i', 'v', '3', '2'): 14054 _codec ("Indeo Video 3"); 14055 caps = gst_caps_new_simple ("video/x-indeo", 14056 "indeoversion", G_TYPE_INT, 3, NULL); 14057 break; 14058 case GST_MAKE_FOURCC ('I', 'V', '4', '1'): 14059 case GST_MAKE_FOURCC ('i', 'v', '4', '1'): 14060 _codec ("Intel Video 4"); 14061 caps = gst_caps_new_simple ("video/x-indeo", 14062 "indeoversion", G_TYPE_INT, 4, NULL); 14063 break; 14064 case FOURCC_dvcp: 14065 case FOURCC_dvc_: 14066 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'): 14067 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'): 14068 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'): 14069 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'): 14070 case GST_MAKE_FOURCC ('d', 'v', '2', '5'): 14071 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'): 14072 _codec ("DV Video"); 14073 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25, 14074 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); 14075 break; 14076 case FOURCC_dv5n: /* DVCPRO50 NTSC */ 14077 case FOURCC_dv5p: /* DVCPRO50 PAL */ 14078 _codec ("DVCPro50 Video"); 14079 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50, 14080 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); 14081 break; 14082 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */ 14083 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */ 14084 _codec ("DVCProHD Video"); 14085 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100, 14086 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); 14087 break; 14088 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '): 14089 _codec ("Apple Graphics (SMC)"); 14090 caps = gst_caps_new_empty_simple ("video/x-smc"); 14091 break; 14092 case GST_MAKE_FOURCC ('V', 'P', '3', '1'): 14093 _codec ("VP3"); 14094 caps = gst_caps_new_empty_simple ("video/x-vp3"); 14095 break; 14096 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'): 14097 _codec ("VP6 Flash"); 14098 caps = gst_caps_new_empty_simple ("video/x-vp6-flash"); 14099 break; 14100 case FOURCC_XiTh: 14101 _codec ("Theora"); 14102 caps = gst_caps_new_empty_simple ("video/x-theora"); 14103 /* theora uses one byte of padding in the data stream because it does not 14104 * allow 0 sized packets while theora does */ 14105 entry->padding = 1; 14106 break; 14107 case FOURCC_drac: 14108 _codec ("Dirac"); 14109 caps = gst_caps_new_empty_simple ("video/x-dirac"); 14110 break; 14111 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'): 14112 _codec ("TIFF still images"); 14113 caps = gst_caps_new_empty_simple ("image/tiff"); 14114 break; 14115 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'): 14116 _codec ("Apple Intermediate Codec"); 14117 caps = gst_caps_from_string ("video/x-apple-intermediate-codec"); 14118 break; 14119 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'): 14120 _codec ("AVID DNxHD"); 14121 caps = gst_caps_from_string ("video/x-dnxhd"); 14122 break; 14123 case FOURCC_VP80: 14124 case FOURCC_vp08: 14125 _codec ("On2 VP8"); 14126 caps = gst_caps_from_string ("video/x-vp8"); 14127 break; 14128 case FOURCC_vp09: 14129 _codec ("Google VP9"); 14130 caps = gst_caps_from_string ("video/x-vp9"); 14131 break; 14132 case FOURCC_apcs: 14133 _codec ("Apple ProRes LT"); 14134 caps = 14135 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt", 14136 NULL); 14137 break; 14138 case FOURCC_apch: 14139 _codec ("Apple ProRes HQ"); 14140 caps = 14141 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq", 14142 NULL); 14143 break; 14144 case FOURCC_apcn: 14145 _codec ("Apple ProRes"); 14146 caps = 14147 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, 14148 "standard", NULL); 14149 break; 14150 case FOURCC_apco: 14151 _codec ("Apple ProRes Proxy"); 14152 caps = 14153 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, 14154 "proxy", NULL); 14155 break; 14156 case FOURCC_ap4h: 14157 _codec ("Apple ProRes 4444"); 14158 caps = 14159 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, 14160 "4444", NULL); 14161 break; 14162 case FOURCC_ap4x: 14163 _codec ("Apple ProRes 4444 XQ"); 14164 caps = 14165 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, 14166 "4444xq", NULL); 14167 break; 14168 case FOURCC_cfhd: 14169 _codec ("GoPro CineForm"); 14170 caps = gst_caps_from_string ("video/x-cineform"); 14171 break; 14172 case FOURCC_vc_1: 14173 case FOURCC_ovc1: 14174 _codec ("VC-1"); 14175 caps = gst_caps_new_simple ("video/x-wmv", 14176 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL); 14177 break; 14178 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'): 14179 default: 14180 { 14181 caps = _get_unknown_codec_name ("video", fourcc); 14182 break; 14183 } 14184 } 14185 14186 if (format != GST_VIDEO_FORMAT_UNKNOWN) { 14187 GstVideoInfo info; 14188 14189 gst_video_info_init (&info); 14190 gst_video_info_set_format (&info, format, entry->width, entry->height); 14191 14192 caps = gst_video_info_to_caps (&info); 14193 *codec_name = gst_pb_utils_get_codec_description (caps); 14194 14195 /* enable clipping for raw video streams */ 14196 stream->need_clip = TRUE; 14197 stream->alignment = 32; 14198 } 14199 14200 return caps; 14201 } 14202 14203 static guint 14204 round_up_pow2 (guint n) 14205 { 14206 n = n - 1; 14207 n = n | (n >> 1); 14208 n = n | (n >> 2); 14209 n = n | (n >> 4); 14210 n = n | (n >> 8); 14211 n = n | (n >> 16); 14212 return n + 1; 14213 } 14214 14215 static GstCaps * 14216 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, 14217 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data, 14218 int len, gchar ** codec_name) 14219 { 14220 GstCaps *caps; 14221 const GstStructure *s; 14222 const gchar *name; 14223 gint endian = 0; 14224 GstAudioFormat format = 0; 14225 gint depth; 14226 14227 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc)); 14228 14229 depth = entry->bytes_per_packet * 8; 14230 14231 switch (fourcc) { 14232 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'): 14233 case FOURCC_raw_: 14234 /* 8-bit audio is unsigned */ 14235 if (depth == 8) 14236 format = GST_AUDIO_FORMAT_U8; 14237 /* otherwise it's signed and big-endian just like 'twos' */ 14238 case FOURCC_twos: 14239 endian = G_BIG_ENDIAN; 14240 /* fall-through */ 14241 case FOURCC_sowt: 14242 { 14243 gchar *str; 14244 14245 if (!endian) 14246 endian = G_LITTLE_ENDIAN; 14247 14248 if (!format) 14249 format = gst_audio_format_build_integer (TRUE, endian, depth, depth); 14250 14251 str = g_strdup_printf ("Raw %d-bit PCM audio", depth); 14252 _codec (str); 14253 g_free (str); 14254 14255 caps = gst_caps_new_simple ("audio/x-raw", 14256 "format", G_TYPE_STRING, gst_audio_format_to_string (format), 14257 "layout", G_TYPE_STRING, "interleaved", NULL); 14258 stream->alignment = GST_ROUND_UP_8 (depth); 14259 stream->alignment = round_up_pow2 (stream->alignment); 14260 break; 14261 } 14262 case GST_MAKE_FOURCC ('f', 'l', '6', '4'): 14263 _codec ("Raw 64-bit floating-point audio"); 14264 caps = gst_caps_new_simple ("audio/x-raw", 14265 "format", G_TYPE_STRING, "F64BE", 14266 "layout", G_TYPE_STRING, "interleaved", NULL); 14267 stream->alignment = 8; 14268 break; 14269 case GST_MAKE_FOURCC ('f', 'l', '3', '2'): 14270 _codec ("Raw 32-bit floating-point audio"); 14271 caps = gst_caps_new_simple ("audio/x-raw", 14272 "format", G_TYPE_STRING, "F32BE", 14273 "layout", G_TYPE_STRING, "interleaved", NULL); 14274 stream->alignment = 4; 14275 break; 14276 case FOURCC_in24: 14277 _codec ("Raw 24-bit PCM audio"); 14278 /* we assume BIG ENDIAN, an enda box will tell us to change this to little 14279 * endian later */ 14280 caps = gst_caps_new_simple ("audio/x-raw", 14281 "format", G_TYPE_STRING, "S24BE", 14282 "layout", G_TYPE_STRING, "interleaved", NULL); 14283 stream->alignment = 4; 14284 break; 14285 case GST_MAKE_FOURCC ('i', 'n', '3', '2'): 14286 _codec ("Raw 32-bit PCM audio"); 14287 caps = gst_caps_new_simple ("audio/x-raw", 14288 "format", G_TYPE_STRING, "S32BE", 14289 "layout", G_TYPE_STRING, "interleaved", NULL); 14290 stream->alignment = 4; 14291 break; 14292 case GST_MAKE_FOURCC ('s', '1', '6', 'l'): 14293 _codec ("Raw 16-bit PCM audio"); 14294 caps = gst_caps_new_simple ("audio/x-raw", 14295 "format", G_TYPE_STRING, "S16LE", 14296 "layout", G_TYPE_STRING, "interleaved", NULL); 14297 stream->alignment = 2; 14298 break; 14299 case FOURCC_ulaw: 14300 _codec ("Mu-law audio"); 14301 caps = gst_caps_new_empty_simple ("audio/x-mulaw"); 14302 break; 14303 case FOURCC_alaw: 14304 _codec ("A-law audio"); 14305 caps = gst_caps_new_empty_simple ("audio/x-alaw"); 14306 break; 14307 case 0x0200736d: 14308 case 0x6d730002: 14309 _codec ("Microsoft ADPCM"); 14310 /* Microsoft ADPCM-ACM code 2 */ 14311 caps = gst_caps_new_simple ("audio/x-adpcm", 14312 "layout", G_TYPE_STRING, "microsoft", NULL); 14313 break; 14314 case 0x1100736d: 14315 case 0x6d730011: 14316 _codec ("DVI/IMA ADPCM"); 14317 caps = gst_caps_new_simple ("audio/x-adpcm", 14318 "layout", G_TYPE_STRING, "dvi", NULL); 14319 break; 14320 case 0x1700736d: 14321 case 0x6d730017: 14322 _codec ("DVI/Intel IMA ADPCM"); 14323 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */ 14324 caps = gst_caps_new_simple ("audio/x-adpcm", 14325 "layout", G_TYPE_STRING, "quicktime", NULL); 14326 break; 14327 case 0x5500736d: 14328 case 0x6d730055: 14329 /* MPEG layer 3, CBR only (pre QT4.1) */ 14330 case FOURCC__mp3: 14331 _codec ("MPEG-1 layer 3"); 14332 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */ 14333 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3, 14334 "mpegversion", G_TYPE_INT, 1, NULL); 14335 break; 14336 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'): 14337 _codec ("MPEG-1 layer 2"); 14338 /* MPEG layer 2 */ 14339 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2, 14340 "mpegversion", G_TYPE_INT, 1, NULL); 14341 break; 14342 case 0x20736d: 14343 case GST_MAKE_FOURCC ('e', 'c', '-', '3'): 14344 _codec ("EAC-3 audio"); 14345 caps = gst_caps_new_simple ("audio/x-eac3", 14346 "framed", G_TYPE_BOOLEAN, TRUE, NULL); 14347 entry->sampled = TRUE; 14348 break; 14349 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode 14350 case FOURCC_ac_3: 14351 _codec ("AC-3 audio"); 14352 caps = gst_caps_new_simple ("audio/x-ac3", 14353 "framed", G_TYPE_BOOLEAN, TRUE, NULL); 14354 entry->sampled = TRUE; 14355 break; 14356 case GST_MAKE_FOURCC ('d', 't', 's', 'c'): 14357 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '): 14358 _codec ("DTS audio"); 14359 caps = gst_caps_new_simple ("audio/x-dts", 14360 "framed", G_TYPE_BOOLEAN, TRUE, NULL); 14361 entry->sampled = TRUE; 14362 break; 14363 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD 14364 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless 14365 _codec ("DTS-HD audio"); 14366 caps = gst_caps_new_simple ("audio/x-dts", 14367 "framed", G_TYPE_BOOLEAN, TRUE, NULL); 14368 entry->sampled = TRUE; 14369 break; 14370 case FOURCC_MAC3: 14371 _codec ("MACE-3"); 14372 caps = gst_caps_new_simple ("audio/x-mace", 14373 "maceversion", G_TYPE_INT, 3, NULL); 14374 break; 14375 case FOURCC_MAC6: 14376 _codec ("MACE-6"); 14377 caps = gst_caps_new_simple ("audio/x-mace", 14378 "maceversion", G_TYPE_INT, 6, NULL); 14379 break; 14380 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'): 14381 /* ogg/vorbis */ 14382 caps = gst_caps_new_empty_simple ("application/ogg"); 14383 break; 14384 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'): 14385 _codec ("DV audio"); 14386 caps = gst_caps_new_empty_simple ("audio/x-dv"); 14387 break; 14388 case FOURCC_mp4a: 14389 _codec ("MPEG-4 AAC audio"); 14390 caps = gst_caps_new_simple ("audio/mpeg", 14391 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE, 14392 "stream-format", G_TYPE_STRING, "raw", NULL); 14393 break; 14394 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'): 14395 _codec ("QDesign Music"); 14396 caps = gst_caps_new_empty_simple ("audio/x-qdm"); 14397 break; 14398 case FOURCC_QDM2: 14399 _codec ("QDesign Music v.2"); 14400 /* FIXME: QDesign music version 2 (no constant) */ 14401 if (FALSE && data) { 14402 caps = gst_caps_new_simple ("audio/x-qdm2", 14403 "framesize", G_TYPE_INT, QT_UINT32 (data + 52), 14404 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40), 14405 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL); 14406 } else { 14407 caps = gst_caps_new_empty_simple ("audio/x-qdm2"); 14408 } 14409 break; 14410 case FOURCC_agsm: 14411 _codec ("GSM audio"); 14412 caps = gst_caps_new_empty_simple ("audio/x-gsm"); 14413 break; 14414 case FOURCC_samr: 14415 _codec ("AMR audio"); 14416 caps = gst_caps_new_empty_simple ("audio/AMR"); 14417 break; 14418 case FOURCC_sawb: 14419 _codec ("AMR-WB audio"); 14420 caps = gst_caps_new_empty_simple ("audio/AMR-WB"); 14421 break; 14422 case FOURCC_ima4: 14423 _codec ("Quicktime IMA ADPCM"); 14424 caps = gst_caps_new_simple ("audio/x-adpcm", 14425 "layout", G_TYPE_STRING, "quicktime", NULL); 14426 break; 14427 case FOURCC_alac: 14428 _codec ("Apple lossless audio"); 14429 caps = gst_caps_new_empty_simple ("audio/x-alac"); 14430 break; 14431 case FOURCC_fLaC: 14432 _codec ("Free Lossless Audio Codec"); 14433 caps = gst_caps_new_simple ("audio/x-flac", 14434 "framed", G_TYPE_BOOLEAN, TRUE, NULL); 14435 break; 14436 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'): 14437 _codec ("QualComm PureVoice"); 14438 caps = gst_caps_from_string ("audio/qcelp"); 14439 break; 14440 case FOURCC_wma_: 14441 case FOURCC_owma: 14442 _codec ("WMA"); 14443 caps = gst_caps_new_empty_simple ("audio/x-wma"); 14444 break; 14445 case FOURCC_opus: 14446 _codec ("Opus"); 14447 caps = gst_caps_new_empty_simple ("audio/x-opus"); 14448 break; 14449 case FOURCC_lpcm: 14450 { 14451 guint32 flags = 0; 14452 guint32 depth = 0; 14453 guint32 width = 0; 14454 GstAudioFormat format; 14455 enum 14456 { 14457 FLAG_IS_FLOAT = 0x1, 14458 FLAG_IS_BIG_ENDIAN = 0x2, 14459 FLAG_IS_SIGNED = 0x4, 14460 FLAG_IS_PACKED = 0x8, 14461 FLAG_IS_ALIGNED_HIGH = 0x10, 14462 FLAG_IS_NON_INTERLEAVED = 0x20 14463 }; 14464 _codec ("Raw LPCM audio"); 14465 14466 if (data && len >= 36) { 14467 depth = QT_UINT32 (data + 24); 14468 flags = QT_UINT32 (data + 28); 14469 width = QT_UINT32 (data + 32) * 8 / entry->n_channels; 14470 } 14471 if ((flags & FLAG_IS_FLOAT) == 0) { 14472 if (depth == 0) 14473 depth = 16; 14474 if (width == 0) 14475 width = 16; 14476 if ((flags & FLAG_IS_ALIGNED_HIGH)) 14477 depth = width; 14478 14479 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ? 14480 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ? 14481 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth); 14482 caps = gst_caps_new_simple ("audio/x-raw", 14483 "format", G_TYPE_STRING, 14484 format != 14485 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) : 14486 "UNKNOWN", "layout", G_TYPE_STRING, 14487 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" : 14488 "interleaved", NULL); 14489 stream->alignment = GST_ROUND_UP_8 (depth); 14490 stream->alignment = round_up_pow2 (stream->alignment); 14491 } else { 14492 if (width == 0) 14493 width = 32; 14494 if (width == 64) { 14495 if (flags & FLAG_IS_BIG_ENDIAN) 14496 format = GST_AUDIO_FORMAT_F64BE; 14497 else 14498 format = GST_AUDIO_FORMAT_F64LE; 14499 } else { 14500 if (flags & FLAG_IS_BIG_ENDIAN) 14501 format = GST_AUDIO_FORMAT_F32BE; 14502 else 14503 format = GST_AUDIO_FORMAT_F32LE; 14504 } 14505 caps = gst_caps_new_simple ("audio/x-raw", 14506 "format", G_TYPE_STRING, gst_audio_format_to_string (format), 14507 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ? 14508 "non-interleaved" : "interleaved", NULL); 14509 stream->alignment = width / 8; 14510 } 14511 break; 14512 } 14513 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'): 14514 /* ? */ 14515 default: 14516 { 14517 caps = _get_unknown_codec_name ("audio", fourcc); 14518 break; 14519 } 14520 } 14521 14522 if (caps) { 14523 GstCaps *templ_caps = 14524 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template); 14525 GstCaps *intersection = gst_caps_intersect (caps, templ_caps); 14526 gst_caps_unref (caps); 14527 gst_caps_unref (templ_caps); 14528 caps = intersection; 14529 } 14530 14531 /* enable clipping for raw audio streams */ 14532 s = gst_caps_get_structure (caps, 0); 14533 name = gst_structure_get_name (s); 14534 if (g_str_has_prefix (name, "audio/x-raw")) { 14535 stream->need_clip = TRUE; 14536 stream->max_buffer_size = 4096 * entry->bytes_per_frame; 14537 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size); 14538 } 14539 return caps; 14540 } 14541 14542 static GstCaps * 14543 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, 14544 QtDemuxStreamStsdEntry * entry, guint32 fourcc, 14545 const guint8 * stsd_entry_data, gchar ** codec_name) 14546 { 14547 GstCaps *caps; 14548 14549 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc)); 14550 14551 switch (fourcc) { 14552 case FOURCC_mp4s: 14553 _codec ("DVD subtitle"); 14554 caps = gst_caps_new_empty_simple ("subpicture/x-dvd"); 14555 stream->need_process = TRUE; 14556 break; 14557 case FOURCC_text: 14558 _codec ("Quicktime timed text"); 14559 goto text; 14560 case FOURCC_tx3g: 14561 _codec ("3GPP timed text"); 14562 text: 14563 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING, 14564 "utf8", NULL); 14565 /* actual text piece needs to be extracted */ 14566 stream->need_process = TRUE; 14567 break; 14568 case FOURCC_stpp: 14569 _codec ("XML subtitles"); 14570 caps = gst_caps_new_empty_simple ("application/ttml+xml"); 14571 break; 14572 default: 14573 { 14574 caps = _get_unknown_codec_name ("text", fourcc); 14575 break; 14576 } 14577 } 14578 return caps; 14579 } 14580 14581 static GstCaps * 14582 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, 14583 QtDemuxStreamStsdEntry * entry, guint32 fourcc, 14584 const guint8 * stsd_entry_data, gchar ** codec_name) 14585 { 14586 GstCaps *caps; 14587 14588 switch (fourcc) { 14589 case FOURCC_m1v: 14590 _codec ("MPEG 1 video"); 14591 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1, 14592 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); 14593 break; 14594 default: 14595 caps = NULL; 14596 break; 14597 } 14598 return caps; 14599 } 14600 14601 static void 14602 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux, 14603 const gchar * system_id) 14604 { 14605 gint i; 14606 14607 if (!qtdemux->protection_system_ids) 14608 qtdemux->protection_system_ids = 14609 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); 14610 /* Check whether we already have an entry for this system ID. */ 14611 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) { 14612 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i); 14613 if (g_ascii_strcasecmp (system_id, id) == 0) { 14614 return; 14615 } 14616 } 14617 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id); 14618 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id, 14619 -1)); 14620 }