summaryrefslogtreecommitdiff
path: root/gst
diff options
context:
space:
mode:
authorThibault Saunier <tsaunier@igalia.com>2020-11-19 17:55:10 -0300
committerThibault Saunier <tsaunier@igalia.com>2020-11-30 17:31:48 -0300
commit142e571c28fe5c3806843bfdf9929cc267739aba (patch)
tree4e19e3b9fae0b3620b1a010904b4a209694ecd92 /gst
parentb3544e24baf06e265e73c850adf35a410e37c617 (diff)
downloadgstreamer-plugins-bad-142e571c28fe5c3806843bfdf9929cc267739aba.tar.gz
transcode: Port to encodebin2
This allows supporting muxing sinks like hlssink2 or splitmux
Diffstat (limited to 'gst')
-rw-r--r--gst/transcode/gsttranscodebin.c63
-rw-r--r--gst/transcode/gsturitranscodebin.c183
2 files changed, 182 insertions, 64 deletions
diff --git a/gst/transcode/gsttranscodebin.c b/gst/transcode/gsttranscodebin.c
index 4ec8b21ac..b6df25d8a 100644
--- a/gst/transcode/gsttranscodebin.c
+++ b/gst/transcode/gsttranscodebin.c
@@ -50,10 +50,22 @@ GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
+/**
+ * GstTranscodeBin!src_%u:
+ *
+ * The sometimes source pad, it will be exposed depending on the
+ * #transcodebin:profile in use.
+ *
+ * Note: in GStreamer 1.18 it was a static
+ * srcpad but in the the 1.20 cycle it was decided that we should make it a
+ * sometimes pad as part of the development of #encodebin2.
+ *
+ * Since: 1.20
+ */
static GstStaticPadTemplate transcode_bin_src_template =
-GST_STATIC_PAD_TEMPLATE ("src",
+GST_STATIC_PAD_TEMPLATE ("src_%u",
GST_PAD_SRC,
- GST_PAD_ALWAYS,
+ GST_PAD_SOMETIMES,
GST_STATIC_CAPS_ANY);
typedef struct
@@ -92,7 +104,6 @@ typedef struct
GstEncodingProfile *profile;
gboolean avoid_reencoding;
GstPad *sinkpad;
- GstPad *srcpad;
GstElement *audio_filter;
GstElement *video_filter;
@@ -364,32 +375,46 @@ decodebin_pad_added_cb (GstElement * decodebin, GstPad * pad,
(GstPadProbeCallback) wait_stream_start_probe, self, NULL);
}
+static void
+encodebin_pad_added_cb (GstElement * encodebin, GstPad * pad, GstElement * self)
+{
+ GstPadTemplate *template;
+ GstPad *new_pad;
+ gchar *name;
+
+ if (!GST_PAD_IS_SRC (pad))
+ return;
+
+ template = gst_element_get_pad_template (self, "src_%u");
+
+ GST_OBJECT_LOCK (self);
+ name = g_strdup_printf ("src_%u", GST_ELEMENT (self)->numsrcpads);
+ GST_OBJECT_UNLOCK (self);
+ new_pad = gst_ghost_pad_new_from_template (name, pad, template);
+ g_free (name);
+ GST_DEBUG_OBJECT (self, "Encodebin exposed srcpad: %" GST_PTR_FORMAT, pad);
+
+ gst_element_add_pad (self, new_pad);
+}
+
static gboolean
make_encodebin (GstTranscodeBin * self)
{
- GstPad *pad;
GST_INFO_OBJECT (self, "making new encodebin");
if (!self->profile)
goto no_profile;
- self->encodebin = gst_element_factory_make ("encodebin", NULL);
+ self->encodebin = gst_element_factory_make ("encodebin2", NULL);
if (!self->encodebin)
goto no_encodebin;
gst_bin_add (GST_BIN (self), self->encodebin);
- g_object_set (self->encodebin, "profile", self->profile, NULL);
- pad = gst_element_get_static_pad (self->encodebin, "src");
- if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad)) {
+ g_signal_connect (self->encodebin, "pad-added",
+ G_CALLBACK (encodebin_pad_added_cb), self);
- gst_object_unref (pad);
- GST_ERROR_OBJECT (self, "Could not ghost %" GST_PTR_FORMAT " srcpad",
- self->encodebin);
-
- return FALSE;
- }
- gst_object_unref (pad);
+ g_object_set (self->encodebin, "profile", self->profile, NULL);
return gst_element_sync_state_with_parent (self->encodebin);
@@ -945,14 +970,6 @@ gst_transcode_bin_init (GstTranscodeBin * self)
gst_object_unref (pad_tmpl);
- pad_tmpl = gst_static_pad_template_get (&transcode_bin_src_template);
-
- self->srcpad = gst_ghost_pad_new_no_target_from_template ("src", pad_tmpl);
- gst_pad_set_active (self->srcpad, TRUE);
- gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
-
- gst_object_unref (pad_tmpl);
-
self->transcoding_streams =
g_ptr_array_new_with_free_func ((GDestroyNotify) transcoding_stream_free);
diff --git a/gst/transcode/gsturitranscodebin.c b/gst/transcode/gsturitranscodebin.c
index 55b3634c0..fc21df48d 100644
--- a/gst/transcode/gsturitranscodebin.c
+++ b/gst/transcode/gsturitranscodebin.c
@@ -104,67 +104,58 @@ post_missing_plugin_error (GstElement * dec, const gchar * element_name)
/* *INDENT-ON* */
static gboolean
-make_transcodebin (GstUriTranscodeBin * self)
+make_dest (GstUriTranscodeBin * self)
{
- GST_INFO_OBJECT (self, "making new transcodebin");
-
- self->transcodebin = gst_element_factory_make ("transcodebin", NULL);
- if (!self->transcodebin)
- goto no_transcodebin;
-
- g_object_set (self->transcodebin, "profile", self->profile,
- "video-filter", self->video_filter,
- "audio-filter", self->audio_filter,
- "avoid-reencoding", self->avoid_reencoding, NULL);
+ GError *err = NULL;
- gst_bin_add (GST_BIN (self), self->transcodebin);
- if (!gst_element_link (self->transcodebin, self->sink)) {
- GST_ERROR ("Could not link transcodbin");
- return FALSE;
+ GST_OBJECT_LOCK (self);
+ if (!self->dest_uri) {
+ GST_INFO_OBJECT (self, "Sink already set: %" GST_PTR_FORMAT, self->sink);
+ goto ok_unlock;
}
- return TRUE;
-
- /* ERRORS */
-no_transcodebin:
- {
- post_missing_plugin_error (GST_ELEMENT_CAST (self), "transcodebin");
-
- GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, (NULL),
- ("No transcodebin element, check your installation"));
-
- return FALSE;
- }
-}
-
-static gboolean
-make_dest (GstUriTranscodeBin * self)
-{
- GError *err = NULL;
+ if (!self->dest_uri)
+ goto ok_unlock;
if (!gst_uri_is_valid (self->dest_uri))
- goto invalid_uri;
+ goto invalid_uri_unlock;
self->sink = gst_element_make_from_uri (GST_URI_SINK, self->dest_uri,
"sink", &err);
if (!self->sink)
- goto no_sink;
+ goto no_sink_unlock;
+ GST_OBJECT_UNLOCK (self);
gst_bin_add (GST_BIN (self), self->sink);
g_object_set (self->sink, "sync", TRUE, "max-lateness", GST_CLOCK_TIME_NONE,
NULL);
+
return TRUE;
-invalid_uri:
+ok_unlock:
+ GST_OBJECT_UNLOCK (self);
+ return TRUE;
+
+invalid_uri_unlock:
{
+ GST_OBJECT_UNLOCK (self);
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
("Invalid URI \"%s\".", self->dest_uri), (NULL));
g_clear_error (&err);
return FALSE;
}
-no_sink:
+invalid_uri:
+ {
+ GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
+ ("Invalid URI \"%s\".", self->source_uri), (NULL));
+ g_clear_error (&err);
+ return FALSE;
+ }
+
+no_sink_unlock:
{
+ GST_OBJECT_UNLOCK (self);
/* whoops, could not create the source element, dig a little deeper to
* figure out what might be wrong. */
if (err != NULL && err->code == GST_URI_ERROR_UNSUPPORTED_PROTOCOL) {
@@ -194,6 +185,69 @@ no_sink:
}
static void
+transcodebin_pad_added_cb (GstElement * transcodebin, GstPad * pad,
+ GstUriTranscodeBin * self)
+{
+
+ GstPad *sinkpad;
+
+ if (GST_PAD_IS_SINK (pad))
+ return;
+
+ make_dest (self);
+ if (!self->sink) {
+ GST_ELEMENT_ERROR (self, CORE, FAILED, (NULL), ("No sink configured."));
+ return;
+ }
+
+ sinkpad = gst_element_get_static_pad (self->sink, "sink");
+ if (!sinkpad) {
+ GST_ELEMENT_ERROR (self, CORE, FAILED, (NULL), ("Sink has not sinkpad?!"));
+ return;
+ }
+
+ if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK) {
+ GST_ERROR_OBJECT (self,
+ "Could not link %" GST_PTR_FORMAT " and %" GST_PTR_FORMAT, pad,
+ sinkpad);
+ /* Let `pad unlinked` error pop up later */
+ }
+}
+
+static gboolean
+make_transcodebin (GstUriTranscodeBin * self)
+{
+ GST_INFO_OBJECT (self, "making new transcodebin");
+
+ self->transcodebin = gst_element_factory_make ("transcodebin", NULL);
+ if (!self->transcodebin)
+ goto no_transcodebin;
+
+ g_signal_connect (self->transcodebin, "pad-added",
+ G_CALLBACK (transcodebin_pad_added_cb), self);
+
+ g_object_set (self->transcodebin, "profile", self->profile,
+ "video-filter", self->video_filter,
+ "audio-filter", self->audio_filter,
+ "avoid-reencoding", self->avoid_reencoding, NULL);
+
+ gst_bin_add (GST_BIN (self), self->transcodebin);
+
+ return TRUE;
+
+ /* ERRORS */
+no_transcodebin:
+ {
+ post_missing_plugin_error (GST_ELEMENT_CAST (self), "transcodebin");
+
+ GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, (NULL),
+ ("No transcodebin element, check your installation"));
+
+ return FALSE;
+ }
+}
+
+static void
src_pad_added_cb (GstElement * src, GstPad * pad, GstUriTranscodeBin * self)
{
GstPad *sinkpad = NULL;
@@ -297,6 +351,52 @@ remove_all_children (GstUriTranscodeBin * self)
}
}
+static void
+set_location_on_muxer_if_sink (GstUriTranscodeBin * self, GstElement * child)
+{
+ GstElementFactory *factory = gst_element_get_factory (child);
+
+ if (!factory)
+ return;
+
+ if (!self->dest_uri)
+ return;
+
+ /* Set out dest URI as location for muxer sinks. */
+ if (!gst_element_factory_list_is_type (factory,
+ GST_ELEMENT_FACTORY_TYPE_MUXER) ||
+ !gst_element_factory_list_is_type (factory,
+ GST_ELEMENT_FACTORY_TYPE_SINK)) {
+
+ return;
+ }
+
+ if (!g_object_class_find_property (G_OBJECT_GET_CLASS (child), "location"))
+ return;
+
+ if (!gst_uri_has_protocol (self->dest_uri, "file")) {
+ GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+ ("Trying to use a not local file with a muxing sink which is not"
+ " supported."), (NULL));
+ return;
+ }
+
+ GST_OBJECT_FLAG_SET (self->transcodebin, GST_ELEMENT_FLAG_SINK);
+ g_object_set (child, "location", &self->dest_uri[strlen ("file://")], NULL);
+ GST_DEBUG_OBJECT (self, "Setting location: %s",
+ &self->dest_uri[strlen ("file://")]);
+}
+
+static void
+deep_element_added (GstBin * bin, GstBin * sub_bin, GstElement * child)
+{
+ GstUriTranscodeBin *self = GST_URI_TRANSCODE_BIN (bin);
+
+ set_location_on_muxer_if_sink (self, child);
+
+ GST_BIN_CLASS (parent_class)->deep_element_added (bin, sub_bin, child);
+}
+
static GstStateChangeReturn
gst_uri_transcode_bin_change_state (GstElement * element,
GstStateChange transition)
@@ -307,16 +407,13 @@ gst_uri_transcode_bin_change_state (GstElement * element,
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
- if (!make_dest (self))
- goto setup_failed;
-
if (!make_transcodebin (self))
goto setup_failed;
if (!make_source (self))
goto setup_failed;
- if (gst_element_set_state (self->sink,
+ if (self->sink && gst_element_set_state (self->sink,
GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
GST_ERROR_OBJECT (self,
"Could not set %" GST_PTR_FORMAT " state to PAUSED", self->sink);
@@ -497,6 +594,7 @@ gst_uri_transcode_bin_class_init (GstUriTranscodeBinClass * klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GstElementClass *gstelement_klass;
+ GstBinClass *gstbin_klass;
object_class->get_property = gst_uri_transcode_bin_get_property;
object_class->set_property = gst_uri_transcode_bin_set_property;
@@ -507,6 +605,9 @@ gst_uri_transcode_bin_class_init (GstUriTranscodeBinClass * klass)
gstelement_klass->change_state =
GST_DEBUG_FUNCPTR (gst_uri_transcode_bin_change_state);
+ gstbin_klass = (GstBinClass *) klass;
+ gstbin_klass->deep_element_added = GST_DEBUG_FUNCPTR (deep_element_added);
+
GST_DEBUG_CATEGORY_INIT (gst_uri_transcodebin_debug, "uritranscodebin", 0,
"UriTranscodebin element");