[vlc-devel] [PATCH 3/4] sout: lock sout_stream_t individually

RĂ©mi Denis-Courmont remi at remlab.net
Sun Oct 11 16:30:38 CEST 2020


The stream output is called from multiple threads without
synchronisation, notably at least one thread per ES decoder. Normally,
the stream output instance (sout_instance_t) lock will serialise all
calls to the first stream output module instance (sout_stream_t) in the
stream output chain.

This is not practical if there is also concurrency within the chain.
One notable case is when the select/duplicate module is used in filter
mode and one of the select/duplicate target is threaded, e.g.:

 #duplicate{dst=transcode{...},dst=transcode{...}}:std{...}

In that example, the standard output can be called from both transcode
filters.

To solve this, add a lock for each element in the stream output chain.
Alternatively, we could drop filter mode from select/duplicate, leaving
only the (more common) output mode where duplicate is the last element
in the chain.
---
 src/stream_output/stream_output.c | 44 +++++++++++++++++++++++++++----
 1 file changed, 39 insertions(+), 5 deletions(-)

diff --git a/src/stream_output/stream_output.c b/src/stream_output/stream_output.c
index e0769dc749..069fe57346 100644
--- a/src/stream_output/stream_output.c
+++ b/src/stream_output/stream_output.c
@@ -736,38 +736,71 @@ static void mrl_Clean( mrl_t *p_mrl )
 
 struct sout_stream_private {
     sout_stream_t stream;
+    vlc_mutex_t lock;
     module_t *module;
 };
 
 #define sout_stream_priv(s) \
         container_of(s, struct sout_stream_private, stream)
 
+static void sout_StreamLock(sout_stream_t *s)
+{
+    vlc_mutex_lock(&sout_stream_priv(s)->lock);
+}
+
+static void sout_StreamUnlock(sout_stream_t *s)
+{
+    vlc_mutex_unlock(&sout_stream_priv(s)->lock);
+}
+
 void *sout_StreamIdAdd(sout_stream_t *s, const es_format_t *fmt)
 {
-    return s->ops->add(s, fmt);
+    void *id;
+
+    sout_StreamLock(s);
+    id = s->ops->add(s, fmt);
+    sout_StreamUnlock(s);
+    return id;
 }
 
 void sout_StreamIdDel(sout_stream_t *s, void *id)
 {
+    sout_StreamLock(s);
     s->ops->del(s, id);
+    sout_StreamUnlock(s);
 }
 
 int sout_StreamIdSend(sout_stream_t *s, void *id, block_t *b)
 {
-    return s->ops->send(s, id, b);
+    int val;
+
+    sout_StreamLock(s);
+    val = s->ops->send(s, id, b);
+    sout_StreamUnlock(s);
+    return val;
 }
 
 void sout_StreamFlush(sout_stream_t *s, void *id)
 {
     if (s->ops->flush != NULL)
+    {
+        sout_StreamLock(s);
         s->ops->flush(s, id);
+        sout_StreamUnlock(s);
+    }
 }
 
 int sout_StreamControlVa(sout_stream_t *s, int i_query, va_list args)
 {
-    if (s->ops->control == NULL)
-        return VLC_EGENERIC;
-    return s->ops->control(s, i_query, args);
+    int val = VLC_EGENERIC;
+
+    if (s->ops->control != NULL)
+    {
+        sout_StreamLock(s);
+        val = s->ops->control(s, i_query, args);
+        sout_StreamUnlock(s);
+    }
+    return val;
 }
 
 /* Destroy a "stream_out" module */
@@ -823,6 +856,7 @@ static sout_stream_t *sout_StreamNew( vlc_object_t *parent, char *psz_name,
     if (unlikely(priv == NULL))
         return NULL;
 
+    vlc_mutex_init(&priv->lock);
     p_stream = &priv->stream;
     p_stream->psz_name = psz_name;
     p_stream->p_cfg    = p_cfg;
-- 
2.28.0



More information about the vlc-devel mailing list