1 /* Quicktime muxer plugin for GStreamer 2 * Copyright (C) 2008-2010 Thiago Santos <thiagoss@embedded.ufcg.edu.br> 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 * Unless otherwise indicated, Source Code is licensed under MIT license. 21 * See further explanation attached in License Statement (distributed in the file 22 * LICENSE). 23 * 24 * Permission is hereby granted, free of charge, to any person obtaining a copy of 25 * this software and associated documentation files (the "Software"), to deal in 26 * the Software without restriction, including without limitation the rights to 27 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 28 * of the Software, and to permit persons to whom the Software is furnished to do 29 * so, subject to the following conditions: 30 * 31 * The above copyright notice and this permission notice shall be included in all 32 * copies or substantial portions of the Software. 33 * 34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 35 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 36 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 37 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 38 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 39 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 40 * SOFTWARE. 41 */ 42 43 #ifndef __GST_QT_MUX_H__ 44 #define __GST_QT_MUX_H__ 45 46 #include <gst/gst.h> 47 #include <gst/base/gstaggregator.h> 48 49 #include "fourcc.h" 50 #include "atoms.h" 51 #include "atomsrecovery.h" 52 #include "gstqtmuxmap.h" 53 54 G_BEGIN_DECLS 55 56 #define GST_TYPE_QT_MUX (gst_qt_mux_get_type()) 57 #define GST_QT_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QT_MUX, GstQTMux)) 58 #define GST_QT_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QT_MUX, GstQTMux)) 59 #define GST_IS_QT_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QT_MUX)) 60 #define GST_IS_QT_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QT_MUX)) 61 #define GST_QT_MUX_CAST(obj) ((GstQTMux*)(obj)) 62 63 64 typedef struct _GstQTMux GstQTMux; 65 typedef struct _GstQTMuxClass GstQTMuxClass; 66 typedef struct _GstQTMuxPad GstQTMuxPad; 67 typedef struct _GstQTMuxPadClass GstQTMuxPadClass; 68 69 /* 70 * GstQTPadPrepareBufferFunc 71 * 72 * Receives a buffer (takes ref) and returns a new buffer that should 73 * replace the passed one. 74 * 75 * Useful for when the pad/datatype needs some manipulation before 76 * being muxed. (Originally added for image/x-jpc support, for which buffers 77 * need to be wrapped into a isom box) 78 */ 79 typedef GstBuffer * (*GstQTPadPrepareBufferFunc) (GstQTMuxPad * pad, 80 GstBuffer * buf, GstQTMux * qtmux); 81 typedef gboolean (*GstQTPadSetCapsFunc) (GstQTMuxPad * pad, GstCaps * caps); 82 typedef GstBuffer * (*GstQTPadCreateEmptyBufferFunc) (GstQTMuxPad * pad, gint64 duration); 83 84 GType gst_qt_mux_pad_get_type (void); 85 86 #define GST_TYPE_QT_MUX_PAD \ 87 (gst_qt_mux_pad_get_type()) 88 #define GST_QT_MUX_PAD(obj) \ 89 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QT_MUX_PAD, GstQTMuxPad)) 90 #define GST_QT_MUX_PAD_CLASS(klass) \ 91 (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QT_MUX_PAD, GstQTMuxPadClass)) 92 #define GST_IS_QT_MUX_PAD(obj) \ 93 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QT_MUX_PAD)) 94 #define GST_IS_QT_MUX_PAD_CLASS(klass) \ 95 (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QT_MUX_PAD)) 96 #define GST_QT_MUX_PAD_CAST(obj) \ 97 ((GstQTMuxPad *)(obj)) 98 99 struct _GstQTMuxPad 100 { 101 GstAggregatorPad parent; 102 103 guint32 trak_timescale; 104 105 /* fourcc id of stream */ 106 guint32 fourcc; 107 /* whether using format that have out of order buffers */ 108 gboolean is_out_of_order; 109 /* if not 0, track with constant sized samples, e.g. raw audio */ 110 guint sample_size; 111 /* make sync table entry */ 112 gboolean sync; 113 /* if it is a sparse stream 114 * (meaning we can't use PTS differences to compute duration) */ 115 gboolean sparse; 116 /* bitrates */ 117 guint32 avg_bitrate, max_bitrate; 118 /* expected sample duration */ 119 guint expected_sample_duration_n; 120 guint expected_sample_duration_d; 121 122 /* for avg bitrate calculation */ 123 guint64 total_bytes; 124 guint64 total_duration; 125 126 GstBuffer *last_buf; 127 /* dts of last_buf */ 128 GstClockTime last_dts; 129 guint64 sample_offset; 130 131 /* TRUE if we saw backward/missing DTS on this 132 * pad (and warned about it */ 133 gboolean warned_empty_duration; 134 135 /* This is compensate for CTTS */ 136 GstClockTime dts_adjustment; 137 138 /* store the first timestamp for comparing with other streams and 139 * know if there are late streams */ 140 /* subjected to dts adjustment */ 141 GstClockTime first_ts; 142 GstClockTime first_dts; 143 144 gint64 dts; /* the signed version of the DTS converted to running time. */ 145 146 /* all the atom and chunk book-keeping is delegated here 147 * unowned/uncounted reference, parent MOOV owns */ 148 AtomTRAK *trak; 149 AtomTRAK *tc_trak; 150 SampleTableEntry *trak_ste; 151 /* fragmented support */ 152 /* meta data book-keeping delegated here */ 153 AtomTRAF *traf; 154 /* fragment buffers */ 155 ATOM_ARRAY (GstBuffer *) fragment_buffers; 156 /* running fragment duration */ 157 gint64 fragment_duration; 158 /* optional fragment index book-keeping */ 159 AtomTFRA *tfra; 160 161 /* Set when tags are received, cleared when written to moov */ 162 gboolean tags_changed; 163 164 GstTagList *tags; 165 166 /* if nothing is set, it won't be called */ 167 GstQTPadPrepareBufferFunc prepare_buf_func; 168 GstQTPadSetCapsFunc set_caps; 169 GstQTPadCreateEmptyBufferFunc create_empty_buffer; 170 171 /* SMPTE timecode */ 172 GstVideoTimeCode *first_tc; 173 GstClockTime first_pts; 174 guint64 tc_pos; 175 176 /* for keeping track in pre-fill mode */ 177 GArray *samples; 178 guint first_cc_sample_size; 179 /* current sample */ 180 GstAdapter *raw_audio_adapter; 181 guint64 raw_audio_adapter_offset; 182 GstClockTime raw_audio_adapter_pts; 183 GstFlowReturn flow_status; 184 185 GstCaps *configured_caps; 186 }; 187 188 struct _GstQTMuxPadClass 189 { 190 GstAggregatorPadClass parent; 191 }; 192 193 #define QTMUX_NO_OF_TS 10 194 195 typedef enum _GstQTMuxState 196 { 197 GST_QT_MUX_STATE_NONE, 198 GST_QT_MUX_STATE_STARTED, 199 GST_QT_MUX_STATE_DATA, 200 GST_QT_MUX_STATE_EOS 201 } GstQTMuxState; 202 203 typedef enum _GstQtMuxMode { 204 GST_QT_MUX_MODE_MOOV_AT_END, 205 GST_QT_MUX_MODE_FRAGMENTED, 206 GST_QT_MUX_MODE_FAST_START, 207 GST_QT_MUX_MODE_ROBUST_RECORDING, 208 GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL, 209 } GstQtMuxMode; 210 211 /** 212 * GstQTMuxFragmentMode: 213 * @GST_QT_MUX_FRAGMENT_DASH_OR_MSS: dash-or-mss 214 * @GST_QT_MUX_FRAGMENT_FIRST_MOOV_THEN_FINALISE: first-moov-then-finalise 215 * @GST_QT_MUX_FRAGMENT_STREAMABLE: streamable (private value) 216 * 217 * Since: 1.20 218 */ 219 typedef enum _GstQTMuxFragmentMode 220 { 221 GST_QT_MUX_FRAGMENT_DASH_OR_MSS = 0, 222 GST_QT_MUX_FRAGMENT_FIRST_MOOV_THEN_FINALISE, 223 GST_QT_MUX_FRAGMENT_STREAMABLE = G_MAXUINT32, /* internal value */ 224 } GstQTMuxFragmentMode; 225 226 struct _GstQTMux 227 { 228 GstAggregator parent; 229 230 /* state */ 231 GstQTMuxState state; 232 233 /* Mux mode, inferred from property 234 * set in gst_qt_mux_start_file() */ 235 GstQtMuxMode mux_mode; 236 /* fragment_mode, controls how fragments are created. Only if 237 * @mux_mode == GST_QT_MUX_MODE_FRAGMENTED */ 238 GstQTMuxFragmentMode fragment_mode; 239 240 /* whether downstream is seekable */ 241 gboolean downstream_seekable; 242 243 /* size of header (prefix, atoms (ftyp, possibly moov, mdat header)) */ 244 guint64 header_size; 245 /* accumulated size of raw media data (not including mdat header) */ 246 guint64 mdat_size; 247 /* position of the moov (for fragmented mode) or reserved moov atom 248 * area (for robust-muxing mode) */ 249 guint64 moov_pos; 250 /* position of mdat atom header (for later updating of size) in 251 * moov-at-end, fragmented and robust-muxing modes */ 252 guint64 mdat_pos; 253 /* position of the mdat atom header of the latest fragment for writing 254 * the default base offset in fragmented mode first-moov-then-finalise and 255 * any other future non-streaming fragmented mode */ 256 guint64 moof_mdat_pos; 257 258 /* keep track of the largest chunk to fine-tune brands */ 259 GstClockTime longest_chunk; 260 261 /* Earliest timestamp across all pads/traks 262 * (unadjusted incoming PTS) */ 263 GstClockTime first_ts; 264 /* Last DTS across all pads (= duration) */ 265 GstClockTime last_dts; 266 267 /* Last pad we used for writing the current chunk */ 268 GstQTMuxPad *current_pad; 269 guint64 current_chunk_size; 270 GstClockTime current_chunk_duration; 271 guint64 current_chunk_offset; 272 273 /* list of buffers to hold for batching inside a single mdat when downstream 274 * is not seekable */ 275 GList *output_buffers; 276 277 /* atom helper objects */ 278 AtomsContext *context; 279 AtomFTYP *ftyp; 280 AtomMOOV *moov; 281 GSList *extra_atoms; /* list of extra top-level atoms (e.g. UUID for xmp) 282 * Stored as AtomInfo structs */ 283 284 /* Set when tags are received, cleared when written to moov */ 285 gboolean tags_changed; 286 287 /* fragmented file index */ 288 AtomMFRA *mfra; 289 290 /* fast start */ 291 FILE *fast_start_file; 292 293 /* moov recovery */ 294 FILE *moov_recov_file; 295 296 /* fragment sequence */ 297 guint32 fragment_sequence; 298 299 /* properties */ 300 guint32 timescale; 301 guint32 trak_timescale; 302 AtomsTreeFlavor flavor; 303 gboolean fast_start; 304 gboolean guess_pts; 305 #ifndef GST_REMOVE_DEPRECATED 306 gint dts_method; 307 #endif 308 gchar *fast_start_file_path; 309 gchar *moov_recov_file_path; 310 guint32 fragment_duration; 311 /* Whether or not to work in 'streamable' mode and not 312 * seek to rewrite headers - only valid for fragmented 313 * mode. Deprecated */ 314 gboolean streamable; 315 316 /* Requested target maximum duration */ 317 GstClockTime reserved_max_duration; 318 /* Estimate of remaining reserved header space (in ns of recording) */ 319 GstClockTime reserved_duration_remaining; 320 /* Multiplier for conversion from reserved_max_duration to bytes */ 321 guint reserved_bytes_per_sec_per_trak; 322 323 guint64 interleave_bytes; 324 GstClockTime interleave_time; 325 gboolean interleave_bytes_set, interleave_time_set; 326 gboolean force_chunks; 327 328 GstClockTime max_raw_audio_drift; 329 330 /* Reserved minimum MOOV size in bytes 331 * This is converted from reserved_max_duration 332 * using the bytes/trak/sec estimate */ 333 guint32 reserved_moov_size; 334 /* Basic size of the moov (static headers + tags) */ 335 guint32 base_moov_size; 336 /* Size of the most recently generated moov header */ 337 guint32 last_moov_size; 338 /* True if the first moov in the ping-pong buffers 339 * is the active one. See gst_qt_mux_robust_recording_rewrite_moov() */ 340 gboolean reserved_moov_first_active; 341 342 /* Tracking of periodic MOOV updates */ 343 GstClockTime last_moov_update; 344 GstClockTime reserved_moov_update_period; 345 GstClockTime muxed_since_last_update; 346 347 gboolean reserved_prefill; 348 349 GstClockTime start_gap_threshold; 350 351 gboolean force_create_timecode_trak; 352 353 /* for request pad naming */ 354 guint video_pads, audio_pads, subtitle_pads, caption_pads; 355 356 /* ohos.ext.func.0016 357 * add additional features to set geographic location information in mp4 file 358 * enable_geolocation is the flag to enable this feature 359 * latitudex10000 is the latitude to set, multiply 10000 for the convenience of calculation. 360 * longitudex10000 is the longitude to set, multiply 10000 for the convenience of calculation. 361 */ 362 #ifdef OHOS_EXT_FUNC 363 gboolean enable_geolocation; 364 gint latitudex10000; 365 gint longitudex10000; 366 #endif 367 368 /* ohos.ext.func.0018 369 * add additional features to set orientationHint in mp4 file. 370 */ 371 #ifdef OHOS_EXT_FUNC 372 guint32 rotation; 373 #endif 374 375 /* ohos.opt.compat.0011 376 * qtmux itself does not handle flush events, so in extreme cases, the buffer is discarded by gstpad 377 * when it is passed forward, but qtmux thinks that the buffer writes the file successfully, 378 * resulting in a file exception. 379 * is_flushing: a flag to tell qtmux, in flushing progress. 380 * flush_lock: is a lock to make sure the flag Operating normally. 381 */ 382 #ifdef OHOS_OPT_COMPAT 383 GMutex flush_lock; 384 gboolean is_flushing; 385 #endif 386 }; 387 388 struct _GstQTMuxClass 389 { 390 GstAggregatorClass parent_class; 391 392 GstQTMuxFormat format; 393 }; 394 395 /* type register helper struct */ 396 typedef struct _GstQTMuxClassParams 397 { 398 GstQTMuxFormatProp *prop; 399 GstCaps *src_caps; 400 GstCaps *video_sink_caps; 401 GstCaps *audio_sink_caps; 402 GstCaps *subtitle_sink_caps; 403 GstCaps *caption_sink_caps; 404 } GstQTMuxClassParams; 405 406 #define GST_QT_MUX_PARAMS_QDATA g_quark_from_static_string("qt-mux-params") 407 408 GType gst_qt_mux_get_type (void); 409 gboolean gst_qt_mux_register (GstPlugin * plugin); 410 411 /* FIXME: ideally classification tag should be added and 412 * registered in gstreamer core gsttaglist 413 * 414 * this tag is a string in the format: entityfourcc://table_num/content 415 * FIXME Shouldn't we add a field for 'language'? 416 */ 417 #define GST_TAG_3GP_CLASSIFICATION "classification" 418 419 G_END_DECLS 420 421 #endif /* __GST_QT_MUX_H__ */ 422