dashsink: cleanup the teardown process

The stream was keeping a reference to the sink, preventing
it to be removed properly by the pipleline bin.
Clean up and simplify the code to get the stream from the pad.
Add more mutex protection against add/remove requested pad.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7916>
This commit is contained in:
Stéphane Cerveau 2024-11-18 12:26:25 +01:00
parent 51a3ef55c9
commit a7a3a80344
2 changed files with 57 additions and 33 deletions

View File

@ -17182,7 +17182,7 @@
"writable": true
},
"mpd-root-path": {
"blurb": "Path where the MPD and its fragents will be written",
"blurb": "Path where the MPD and its fragments will be written",
"conditionally-available": false,
"construct": false,
"construct-only": false,

View File

@ -96,6 +96,10 @@
GST_DEBUG_CATEGORY_STATIC (gst_dash_sink_debug);
#define GST_CAT_DEFAULT gst_dash_sink_debug
#define GST_DASHSINK_LOCK(s) g_mutex_lock(&(s)->lock)
#define GST_DASHSINK_UNLOCK(s) g_mutex_unlock(&(s)->lock)
#define GST_DASHSINK_MPD_LOCK(s) g_mutex_lock(&(s)->mpd_lock)
#define GST_DASHSINK_MPD_UNLOCK(s) g_mutex_unlock(&(s)->mpd_lock)
/**
* GstDashSinkMuxerType:
* @GST_DASH_SINK_MUXER_TS: Use mpegtsmux
@ -246,6 +250,7 @@ typedef union _GstDashSinkStreamInfo
struct _GstDashSink
{
GstBin bin;
GMutex lock;
GMutex mpd_lock;
gchar *location;
gchar *mpd_filename;
@ -307,9 +312,17 @@ GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
static GQuark PAD_CONTEXT;
static void
_do_init (void)
{
PAD_CONTEXT = g_quark_from_static_string ("splitmuxsink-pad-context");
GST_DEBUG_CATEGORY_INIT (gst_dash_sink_debug, "dashsink", 0, "DashSink");
}
#define gst_dash_sink_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstDashSink, gst_dash_sink, GST_TYPE_BIN,
GST_DEBUG_CATEGORY_INIT (gst_dash_sink_debug, "dashsink", 0, "DashSink"));
G_DEFINE_TYPE_WITH_CODE (GstDashSink, gst_dash_sink, GST_TYPE_BIN, _do_init ());
GST_ELEMENT_REGISTER_DEFINE (dashsink, "dashsink", GST_RANK_NONE,
gst_dash_sink_get_type ());
@ -325,20 +338,6 @@ static GstPad *gst_dash_sink_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static void gst_dash_sink_release_pad (GstElement * element, GstPad * pad);
static GstDashSinkStream *
gst_dash_sink_stream_from_pad (GList * streams, GstPad * pad)
{
GList *l;
GstDashSinkStream *stream = NULL;
for (l = streams; l != NULL; l = l->next) {
stream = l->data;
if (stream->pad == pad)
return stream;
}
return NULL;
}
static GstDashSinkStream *
gst_dash_sink_stream_from_splitmuxsink (GList * streams, GstElement * element)
{
@ -387,12 +386,10 @@ static void
gst_dash_sink_stream_free (gpointer s)
{
GstDashSinkStream *stream = (GstDashSinkStream *) s;
g_object_unref (stream->sink);
g_free (stream->current_segment_location);
g_free (stream->representation_id);
g_free (stream->mimetype);
g_free (stream->codec);
g_free (stream);
}
@ -415,6 +412,7 @@ gst_dash_sink_finalize (GObject * object)
if (sink->mpd_client)
gst_mpd_client_free (sink->mpd_client);
g_mutex_clear (&sink->mpd_lock);
g_mutex_clear (&sink->lock);
g_list_free_full (sink->streams, gst_dash_sink_stream_free);
@ -507,7 +505,7 @@ gst_dash_sink_class_init (GstDashSinkClass * klass)
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_MPD_ROOT_PATH,
g_param_spec_string ("mpd-root-path", "MPD Root Path",
"Path where the MPD and its fragents will be written",
"Path where the MPD and its fragments will be written",
DEFAULT_MPD_ROOT_PATH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_MPD_BASEURL,
g_param_spec_string ("mpd-baseurl", "MPD BaseURL",
@ -683,6 +681,10 @@ gst_dash_sink_add_splitmuxsink (GstDashSink * sink, GstDashSinkStream * stream)
}
gst_bin_add (GST_BIN (sink), stream->splitmuxsink);
/* We need to keep a reference to the splitmuxsink to keep it alive after it has been removed by the bin.
* We need it to be alive until the stream is removed.
*/
gst_object_ref (stream->splitmuxsink);
if (!sink->use_segment_list)
stream->current_segment_id = 1;
@ -721,6 +723,7 @@ gst_dash_sink_init (GstDashSink * sink)
sink->period_duration = DEFAULT_MPD_PERIOD_DURATION;
sink->suggested_presentation_delay = DEFAULT_MPD_SUGGESTED_PRESENTATION_DELAY;
g_mutex_init (&sink->lock);
g_mutex_init (&sink->mpd_lock);
GST_OBJECT_FLAG_SET (sink, GST_ELEMENT_FLAG_SINK);
@ -893,13 +896,13 @@ gst_dash_sink_write_mpd_file (GstDashSink * sink,
GOutputStream *file_stream = NULL;
gsize bytes_to_write;
g_mutex_lock (&sink->mpd_lock);
GST_DASHSINK_MPD_LOCK (sink);
gst_dash_sink_generate_mpd_content (sink, current_stream);
if (!gst_mpd_client_get_xml_content (sink->mpd_client, &mpd_content, &size)) {
g_mutex_unlock (&sink->mpd_lock);
return;
}
g_mutex_unlock (&sink->mpd_lock);
GST_DASHSINK_MPD_UNLOCK (sink);
if (sink->mpd_root_path)
mpd_filepath =
@ -997,8 +1000,9 @@ gst_dash_sink_request_new_pad (GstElement * element, GstPadTemplate * templ,
GstPad *peer = NULL;
const gchar *split_pad_name = pad_name;
GST_DASHSINK_LOCK (sink);
stream = g_new0 (GstDashSinkStream, 1);
stream->sink = g_object_ref (sink);
stream->sink = sink;
if (g_str_has_prefix (templ->name_template, "video")) {
stream->type = DASH_SINK_STREAM_TYPE_VIDEO;
stream->adaptation_set_id = ADAPTATION_SET_ID_VIDEO;
@ -1017,10 +1021,8 @@ gst_dash_sink_request_new_pad (GstElement * element, GstPadTemplate * templ,
stream->representation_id =
gst_dash_sink_stream_get_next_name (sink->streams, stream->type);
stream->mimetype = g_strdup (dash_muxer_list[sink->muxer].mimetype);
if (!gst_dash_sink_add_splitmuxsink (sink, stream)) {
GST_ERROR_OBJECT (sink,
"Unable to create splitmuxsink element for pad template name %s",
@ -1032,24 +1034,27 @@ gst_dash_sink_request_new_pad (GstElement * element, GstPadTemplate * templ,
peer = gst_element_request_pad_simple (stream->splitmuxsink, split_pad_name);
if (!peer) {
GST_ERROR_OBJECT (sink, "Unable to request pad name %s", split_pad_name);
GST_DASHSINK_UNLOCK (sink);
return NULL;
}
pad = gst_ghost_pad_new_from_template (pad_name, peer, templ);
g_object_set_qdata ((GObject *) (pad), PAD_CONTEXT, stream);
stream->buffer_probe = gst_pad_add_probe (pad,
GST_PAD_PROBE_TYPE_BUFFER, _dash_sink_buffers_probe, stream, NULL);
gst_pad_set_active (pad, TRUE);
gst_element_add_pad (element, pad);
gst_object_unref (peer);
stream->pad = pad;
stream->buffer_probe = gst_pad_add_probe (stream->pad,
GST_PAD_PROBE_TYPE_BUFFER, _dash_sink_buffers_probe, stream, NULL);
sink->streams = g_list_append (sink->streams, stream);
GST_DEBUG_OBJECT (sink, "Adding a new stream with id %s",
stream->representation_id);
done:
GST_DASHSINK_UNLOCK (sink);
return pad;
}
@ -1059,9 +1064,12 @@ gst_dash_sink_release_pad (GstElement * element, GstPad * pad)
GstDashSink *sink = GST_DASH_SINK (element);
GstPad *peer;
GstDashSinkStream *stream =
gst_dash_sink_stream_from_pad (sink->streams, pad);
(GstDashSinkStream *) (g_object_get_qdata ((GObject *) (pad),
PAD_CONTEXT));
g_return_if_fail (stream != NULL);
GST_DASHSINK_LOCK (sink);
if (stream == NULL)
goto beach;
peer = gst_pad_get_peer (pad);
if (peer) {
@ -1078,9 +1086,23 @@ gst_dash_sink_release_pad (GstElement * element, GstPad * pad)
gst_element_remove_pad (element, pad);
gst_pad_set_active (pad, FALSE);
stream->pad = NULL;
if (stream->splitmuxsink) {
gst_element_set_locked_state (stream->splitmuxsink, TRUE);
gst_element_set_state (stream->splitmuxsink, GST_STATE_NULL);
gst_bin_remove (GST_BIN (sink), stream->splitmuxsink);
gst_object_unref (stream->splitmuxsink);
}
/* Remove the stream from our consideration */
sink->streams = g_list_remove (sink->streams, stream);
gst_dash_sink_stream_free (stream);
gst_object_unref (pad);
beach:
GST_DASHSINK_UNLOCK (sink);
}
static GstStateChangeReturn
@ -1120,7 +1142,7 @@ gst_dash_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstDashSink *sink = GST_DASH_SINK (object);
GST_DASHSINK_LOCK (sink);
switch (prop_id) {
case PROP_MPD_FILENAME:
g_free (sink->mpd_filename);
@ -1165,6 +1187,7 @@ gst_dash_sink_set_property (GObject * object, guint prop_id,
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_DASHSINK_UNLOCK (sink);
}
static void
@ -1172,7 +1195,7 @@ gst_dash_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstDashSink *sink = GST_DASH_SINK (object);
GST_DASHSINK_LOCK (sink);
switch (prop_id) {
case PROP_MPD_FILENAME:
g_value_set_string (value, sink->mpd_filename);
@ -1214,4 +1237,5 @@ gst_dash_sink_get_property (GObject * object, guint prop_id,
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_DASHSINK_UNLOCK (sink);
}