summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2018-01-18 18:36:27 +0200
committerSebastian Dröge <sebastian@centricular.com>2018-01-23 16:40:23 +0200
commitc71cd08d0edf39c0eb6be9b6458ea7ac8ac2b412 (patch)
tree3fc366c4e0b58aba90f9f1b928c86d0759f0e291
parentf4594382780f967df9e66d4b587e27e769ae5c87 (diff)
qtmux: Allow configuring trak timescale per pad/trak
It generally makes not much sense to configure it for all pads/traks at once as this value is usually different for each of them. As such, add a new property on the pads in addition to the existing property on the whole muxer. https://bugzilla.gnome.org/show_bug.cgi?id=792649
-rw-r--r--gst/isomp4/gstqtmux.c156
1 files changed, 140 insertions, 16 deletions
diff --git a/gst/isomp4/gstqtmux.c b/gst/isomp4/gstqtmux.c
index f9364f3ad..e97228506 100644
--- a/gst/isomp4/gstqtmux.c
+++ b/gst/isomp4/gstqtmux.c
@@ -65,9 +65,10 @@
* The fragmented file features defined (only) in ISO Base Media are used by
* ISMV files making up (a.o.) Smooth Streaming (ismlmux).
*
- * A few properties (#GstQTMux:movie-timescale, #GstQTMux:trak-timescale) allow
- * adjusting some technical parameters, which might be useful in (rare) cases to
- * resolve compatibility issues in some situations.
+ * A few properties (#GstQTMux:movie-timescale, #GstQTMux:trak-timescale,
+ * #GstQTMuxPad:trak-timescale) allow adjusting some technical parameters,
+ * which might be useful in (rare) cases to resolve compatibility issues in
+ * some situations.
*
* Some other properties influence the result more fundamentally.
* A typical mov/mp4 file's metadata (aka moov) is located at the end of the
@@ -247,6 +248,115 @@ gst_qt_mux_dts_method_get_type (void)
(gst_qt_mux_dts_method_get_type ())
#endif
+enum
+{
+ PROP_PAD_0,
+ PROP_PAD_TRAK_TIMESCALE,
+};
+
+#define DEFAULT_PAD_TRAK_TIMESCALE 0
+
+GType gst_qt_mux_pad_get_type (void);
+
+#define GST_TYPE_QT_MUX_PAD \
+ (gst_qt_mux_pad_get_type())
+#define GST_QT_MUX_PAD(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QT_MUX_PAD, GstQTMuxPad))
+#define GST_QT_MUX_PAD_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QT_MUX_PAD, GstQTMuxPadClass))
+#define GST_IS_QT_MUX_PAD(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QT_MUX_PAD))
+#define GST_IS_QT_MUX_PAD_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QT_MUX_PAD))
+#define GST_QT_MUX_PAD_CAST(obj) \
+ ((GstQTMuxPad *)(obj))
+
+typedef struct _GstQTMuxPad GstQTMuxPad;
+typedef struct _GstQTMuxPadClass GstQTMuxPadClass;
+
+struct _GstQTMuxPad
+{
+ GstPad parent;
+
+ guint32 trak_timescale;
+};
+
+struct _GstQTMuxPadClass
+{
+ GstPadClass parent;
+};
+
+G_DEFINE_TYPE (GstQTMuxPad, gst_qt_mux_pad, GST_TYPE_PAD);
+
+static void
+gst_qt_mux_pad_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstQTMuxPad *pad = GST_QT_MUX_PAD_CAST (object);
+
+ GST_OBJECT_LOCK (pad);
+ switch (prop_id) {
+ case PROP_PAD_TRAK_TIMESCALE:
+ pad->trak_timescale = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ GST_OBJECT_UNLOCK (pad);
+}
+
+static void
+gst_qt_mux_pad_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstQTMuxPad *pad = GST_QT_MUX_PAD_CAST (object);
+
+ GST_OBJECT_LOCK (pad);
+ switch (prop_id) {
+ case PROP_PAD_TRAK_TIMESCALE:
+ g_value_set_uint (value, pad->trak_timescale);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ GST_OBJECT_UNLOCK (pad);
+}
+
+static void
+gst_qt_mux_pad_class_init (GstQTMuxPadClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+
+ gobject_class->get_property = gst_qt_mux_pad_get_property;
+ gobject_class->set_property = gst_qt_mux_pad_set_property;
+
+ g_object_class_install_property (gobject_class, PROP_PAD_TRAK_TIMESCALE,
+ g_param_spec_uint ("trak-timescale", "Track timescale",
+ "Timescale to use for this pad's trak (units per second, 0 is automatic)",
+ 0, G_MAXUINT32, DEFAULT_PAD_TRAK_TIMESCALE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_qt_mux_pad_init (GstQTMuxPad * pad)
+{
+ pad->trak_timescale = DEFAULT_PAD_TRAK_TIMESCALE;
+}
+
+static guint32
+gst_qt_mux_pad_get_timescale (GstQTMuxPad * pad)
+{
+ guint32 timescale;
+
+ GST_OBJECT_LOCK (pad);
+ timescale = pad->trak_timescale;
+ GST_OBJECT_UNLOCK (pad);
+
+ return timescale;
+}
+
/* QTMux signals and args */
enum
{
@@ -364,20 +474,23 @@ gst_qt_mux_base_init (gpointer g_class)
gst_element_class_add_pad_template (element_class, srctempl);
if (params->audio_sink_caps) {
- audiosinktempl = gst_pad_template_new ("audio_%u",
- GST_PAD_SINK, GST_PAD_REQUEST, params->audio_sink_caps);
+ audiosinktempl = gst_pad_template_new_with_gtype ("audio_%u",
+ GST_PAD_SINK, GST_PAD_REQUEST, params->audio_sink_caps,
+ GST_TYPE_QT_MUX_PAD);
gst_element_class_add_pad_template (element_class, audiosinktempl);
}
if (params->video_sink_caps) {
- videosinktempl = gst_pad_template_new ("video_%u",
- GST_PAD_SINK, GST_PAD_REQUEST, params->video_sink_caps);
+ videosinktempl = gst_pad_template_new_with_gtype ("video_%u",
+ GST_PAD_SINK, GST_PAD_REQUEST, params->video_sink_caps,
+ GST_TYPE_QT_MUX_PAD);
gst_element_class_add_pad_template (element_class, videosinktempl);
}
if (params->subtitle_sink_caps) {
- subtitlesinktempl = gst_pad_template_new ("subtitle_%u",
- GST_PAD_SINK, GST_PAD_REQUEST, params->subtitle_sink_caps);
+ subtitlesinktempl = gst_pad_template_new_with_gtype ("subtitle_%u",
+ GST_PAD_SINK, GST_PAD_REQUEST, params->subtitle_sink_caps,
+ GST_TYPE_QT_MUX_PAD);
gst_element_class_add_pad_template (element_class, subtitlesinktempl);
}
@@ -4698,6 +4811,7 @@ gst_qt_mux_audio_sink_set_caps (GstQTPad * qtpad, GstCaps * caps)
AtomInfo *ext_atom = NULL;
gint constant_size = 0;
const gchar *stream_format;
+ guint32 timescale;
/* does not go well to renegotiate stream mid-way, unless
* the old caps are a subset of the new one (this means upstream
@@ -5020,14 +5134,18 @@ gst_qt_mux_audio_sink_set_caps (GstQTPad * qtpad, GstCaps * caps)
if (!entry.fourcc)
goto refuse_caps;
+ timescale = gst_qt_mux_pad_get_timescale (GST_QT_MUX_PAD_CAST (pad));
+ if (!timescale && qtmux->trak_timescale)
+ timescale = qtmux->trak_timescale;
+ else if (!timescale)
+ timescale = entry.sample_rate;
+
/* ok, set the pad info accordingly */
qtpad->fourcc = entry.fourcc;
qtpad->sample_size = constant_size;
qtpad->trak_ste =
(SampleTableEntry *) atom_trak_set_audio_type (qtpad->trak,
- qtmux->context, &entry,
- qtmux->trak_timescale ? qtmux->trak_timescale : entry.sample_rate,
- ext_atom, constant_size);
+ qtmux->context, &entry, timescale, ext_atom, constant_size);
gst_object_unref (qtmux);
return TRUE;
@@ -5128,9 +5246,13 @@ gst_qt_mux_video_sink_set_caps (GstQTPad * qtpad, GstCaps * caps)
* as well as a fair duration */
qtpad->expected_sample_duration_n = framerate_num;
qtpad->expected_sample_duration_d = framerate_den;
- rate = qtmux->trak_timescale ?
- qtmux->trak_timescale : atom_framerate_to_timescale (framerate_num,
- framerate_den);
+
+ rate = gst_qt_mux_pad_get_timescale (GST_QT_MUX_PAD_CAST (pad));
+ if (!rate && qtmux->trak_timescale)
+ rate = qtmux->trak_timescale;
+ else if (!rate)
+ rate = atom_framerate_to_timescale (framerate_num, framerate_den);
+
GST_DEBUG_OBJECT (qtmux, "Rate of video track selected: %" G_GUINT32_FORMAT,
rate);
@@ -5825,7 +5947,9 @@ gst_qt_mux_request_new_pad (GstElement * element,
GST_DEBUG_OBJECT (qtmux, "Requested pad: %s", name);
/* create pad and add to collections */
- newpad = gst_pad_new_from_template (templ, name);
+ newpad =
+ g_object_new (GST_TYPE_QT_MUX_PAD, "name", name, "direction",
+ templ->direction, "template", templ, NULL);
g_free (name);
collect_pad = (GstQTPad *)
gst_collect_pads_add_pad (qtmux->collect, newpad, sizeof (GstQTPad),