1 /* GStreamer 2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public 15 * License along with this library; if not, write to the 16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20 21 #ifndef __GST_QTDEMUX_H__ 22 #define __GST_QTDEMUX_H__ 23 24 #include <gst/gst.h> 25 #include <gst/base/gstadapter.h> 26 #include <gst/base/gstflowcombiner.h> 27 #include "gstisoff.h" 28 29 G_BEGIN_DECLS 30 31 #define GST_TYPE_QTDEMUX \ 32 (gst_qtdemux_get_type()) 33 #define GST_QTDEMUX(obj) \ 34 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QTDEMUX,GstQTDemux)) 35 #define GST_QTDEMUX_CLASS(klass) \ 36 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QTDEMUX,GstQTDemuxClass)) 37 #define GST_IS_QTDEMUX(obj) \ 38 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QTDEMUX)) 39 #define GST_IS_QTDEMUX_CLASS(klass) \ 40 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QTDEMUX)) 41 42 #define GST_QTDEMUX_CAST(obj) ((GstQTDemux *)(obj)) 43 44 /* qtdemux produces these for atoms it cannot parse */ 45 #define GST_QT_DEMUX_PRIVATE_TAG "private-qt-tag" 46 #define GST_QT_DEMUX_CLASSIFICATION_TAG "classification" 47 48 typedef struct _GstQTDemux GstQTDemux; 49 typedef struct _GstQTDemuxClass GstQTDemuxClass; 50 typedef struct _QtDemuxStream QtDemuxStream; 51 52 enum QtDemuxState 53 { 54 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */ 55 QTDEMUX_STATE_HEADER, /* Parsing the header */ 56 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */ 57 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */ 58 }; 59 60 struct _GstQTDemux { 61 GstElement element; 62 63 /* Global state */ 64 enum QtDemuxState state; 65 66 /* static sink pad */ 67 GstPad *sinkpad; 68 69 /* TRUE if pull-based */ 70 gboolean pullbased; 71 72 gboolean posted_redirect; 73 74 /* Protect pad exposing from flush event */ 75 GMutex expose_lock; 76 77 /* list of QtDemuxStream */ 78 GPtrArray *active_streams; 79 GPtrArray *old_streams; 80 81 gint n_video_streams; 82 gint n_audio_streams; 83 gint n_sub_streams; 84 85 GstFlowCombiner *flowcombiner; 86 87 /* Incoming stream group-id to set on downstream STREAM_START events. 88 * If upstream doesn't contain one, a global one will be generated */ 89 gboolean have_group_id; 90 guint group_id; 91 92 guint major_brand; 93 GstBuffer *comp_brands; 94 95 /* [moov] header. 96 * FIXME : This is discarded just after it's created. Just move it 97 * to a temporary variable ? */ 98 GNode *moov_node; 99 100 /* FIXME : This is never freed. It is only assigned once. memleak ? */ 101 GNode *moov_node_compressed; 102 103 /* Set to TRUE when the [moov] header has been fully parsed */ 104 gboolean got_moov; 105 106 /* Global timescale for the incoming stream. Use the QTTIME macros 107 * to convert values to/from GstClockTime */ 108 guint32 timescale; 109 110 /* Global duration (in global timescale). Use QTTIME macros to get GstClockTime */ 111 guint64 duration; 112 113 /* Total size of header atoms. Used to calculate fallback overall bitrate */ 114 guint header_size; 115 116 GstTagList *tag_list; 117 118 /* configured playback region */ 119 GstSegment segment; 120 121 /* PUSH-BASED only: If the initial segment event, or a segment consequence of 122 * a seek or incoming TIME segment from upstream needs to be pushed. This 123 * variable is used instead of pushing the event directly because at that 124 * point we may not have yet emitted the srcpads. */ 125 gboolean need_segment; 126 127 guint32 segment_seqnum; 128 129 /* flag to indicate that we're working with a smoothstreaming fragment 130 * Mss doesn't have 'moov' or any information about the streams format, 131 * requiring qtdemux to expose and create the streams */ 132 gboolean mss_mode; 133 134 /* Set to TRUE if the incoming stream is either a MSS stream or 135 * a Fragmented MP4 (containing the [mvex] atom in the header) */ 136 gboolean fragmented; 137 138 /* PULL-BASED only : If TRUE there is a pending seek */ 139 gboolean fragmented_seek_pending; 140 141 /* PULL-BASED : offset of first [moof] or of fragment to seek to 142 * PUSH-BASED : offset of latest [moof] */ 143 guint64 moof_offset; 144 145 /* MSS streams have a single media that is unspecified at the atoms, so 146 * upstream provides it at the caps */ 147 GstCaps *media_caps; 148 149 /* Set to TRUE when all streams have been exposed */ 150 gboolean exposed; 151 152 gint64 chapters_track_id; 153 154 /* protection support */ 155 GPtrArray *protection_system_ids; /* Holds identifiers of all content protection systems for all tracks */ 156 GQueue protection_event_queue; /* holds copy of upstream protection events */ 157 guint64 cenc_aux_info_offset; 158 guint8 *cenc_aux_info_sizes; 159 guint32 cenc_aux_sample_count; 160 gchar *preferred_protection_system_id; 161 162 /* Whether the parent bin is streams-aware, meaning we can 163 * add/remove streams at any point in time */ 164 gboolean streams_aware; 165 166 /* 167 * ALL VARIABLES BELOW ARE ONLY USED IN PUSH-BASED MODE 168 */ 169 GstAdapter *adapter; 170 guint neededbytes; 171 guint todrop; 172 /* Used to store data if [mdat] is before the headers */ 173 GstBuffer *mdatbuffer; 174 /* Amount of bytes left to read in the current [mdat] */ 175 guint64 mdatleft, mdatsize; 176 177 /* When restoring the mdat to the adapter, this buffer stores any 178 * trailing data that was after the last atom parsed as it has to be 179 * restored later along with the correct offset. Used in fragmented 180 * scenario where mdat/moof are one after the other in any order. 181 * 182 * Check https://bugzilla.gnome.org/show_bug.cgi?id=710623 */ 183 GstBuffer *restoredata_buffer; 184 guint64 restoredata_offset; 185 186 /* The current offset in bytes from upstream. 187 * Note: While it makes complete sense when we are PULL-BASED (pulling 188 * in BYTES from upstream) and PUSH-BASED with a BYTE SEGMENT (receiving 189 * buffers with actual offsets), it is undefined in PUSH-BASED with a 190 * TIME SEGMENT */ 191 guint64 offset; 192 193 /* offset of the mdat atom */ 194 guint64 mdatoffset; 195 /* Offset of the first mdat */ 196 guint64 first_mdat; 197 /* offset of last [moov] seen */ 198 guint64 last_moov_offset; 199 200 /* If TRUE, qtdemux received upstream newsegment in TIME format 201 * which likely means that upstream is driving the pipeline (such as 202 * adaptive demuxers or dlna sources) */ 203 gboolean upstream_format_is_time; 204 205 /* Seqnum of the seek event sent upstream. Will be used to 206 * detect incoming FLUSH events corresponding to that */ 207 guint32 offset_seek_seqnum; 208 209 /* UPSTREAM BYTE: Requested upstream byte seek offset. 210 * Currently it is only used to check if an incoming BYTE SEGMENT 211 * corresponds to a seek event that was sent upstream */ 212 gint64 seek_offset; 213 214 /* UPSTREAM BYTE: Requested start/stop TIME values from 215 * downstream. 216 * Used to set on the downstream segment once the corresponding upstream 217 * BYTE SEEK has succeeded */ 218 gint64 push_seek_start; 219 gint64 push_seek_stop; 220 221 #if 0 222 /* gst index support */ 223 GstIndex *element_index; 224 gint index_id; 225 #endif 226 227 /* Whether upstream is seekable in BYTES */ 228 gboolean upstream_seekable; 229 /* UPSTREAM BYTE: Size of upstream content. 230 * Note : This is only computed once ! If upstream grows in the meantime 231 * it will not be updated */ 232 gint64 upstream_size; 233 234 /* UPSTREAM TIME : Contains the PTS (if any) of the 235 * buffer that contains a [moof] header. Will be used to establish 236 * the actual PTS of the samples contained within that fragment. */ 237 guint64 fragment_start; 238 /* UPSTREAM TIME : The offset in bytes of the [moof] 239 * header start. 240 * Note : This is not computed from the GST_BUFFER_OFFSET field */ 241 guint64 fragment_start_offset; 242 243 /* These two fields are used to perform an implicit seek when a fragmented 244 * file whose first tfdt is not zero. This way if the first fragment starts 245 * at 1 hour, the user does not have to wait 1 hour or perform a manual seek 246 * for the image to move and the sound to play. 247 * 248 * This implicit seek is only done if the first parsed fragment has a non-zero 249 * decode base time and a seek has not been received previously, hence these 250 * fields. */ 251 gboolean received_seek; 252 gboolean first_moof_already_parsed; 253 }; 254 255 struct _GstQTDemuxClass { 256 GstElementClass parent_class; 257 }; 258 259 GType gst_qtdemux_get_type (void); 260 261 G_END_DECLS 262 263 #endif /* __GST_QTDEMUX_H__ */ 264