mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 03:00:35 +00:00
transcode: Port to encodebin2
This allows supporting muxing sinks like hlssink2 or splitmux
This commit is contained in:
parent
b3544e24ba
commit
142e571c28
3 changed files with 189 additions and 66 deletions
|
@ -220692,6 +220692,11 @@
|
|||
"caps": "ANY",
|
||||
"direction": "src",
|
||||
"presence": "always"
|
||||
},
|
||||
"src_%%u": {
|
||||
"caps": "ANY",
|
||||
"direction": "src",
|
||||
"presence": "sometimes"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -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,33 +375,47 @@ 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_signal_connect (self->encodebin, "pad-added",
|
||||
G_CALLBACK (encodebin_pad_added_cb), self);
|
||||
|
||||
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)) {
|
||||
|
||||
gst_object_unref (pad);
|
||||
GST_ERROR_OBJECT (self, "Could not ghost %" GST_PTR_FORMAT " srcpad",
|
||||
self->encodebin);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
gst_object_unref (pad);
|
||||
|
||||
return gst_element_sync_state_with_parent (self->encodebin);
|
||||
|
||||
/* ERRORS */
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -103,68 +103,59 @@ post_missing_plugin_error (GstElement * dec, const gchar * element_name)
|
|||
}
|
||||
/* *INDENT-ON* */
|
||||
|
||||
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_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);
|
||||
if (!gst_element_link (self->transcodebin, self->sink)) {
|
||||
GST_ERROR ("Could not link transcodbin");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
if (!self->dest_uri) {
|
||||
GST_INFO_OBJECT (self, "Sink already set: %" GST_PTR_FORMAT, self->sink);
|
||||
goto ok_unlock;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -193,6 +184,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)
|
||||
{
|
||||
|
@ -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");
|
||||
|
||||
|
|
Loading…
Reference in a new issue