• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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