From 0f9fee360382c4f06d739ccf9046838cf1fca9e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= <remi@remlab.net>
Date: Sun, 27 Sep 2015 19:41:14 +0300
Subject: [PATCH] picture_pool: add picture_pool_Wait()

This variant of picture_pool_Get() sleeps until a picture is available.
---
 include/vlc_picture_pool.h | 11 +++++++++++
 src/libvlccore.sym         |  1 +
 src/misc/picture_pool.c    | 37 +++++++++++++++++++++++++++++++++++++
 src/test/picture_pool.c    |  8 ++++++++
 src/video_output/display.c |  1 +
 5 files changed, 58 insertions(+)

diff --git a/include/vlc_picture_pool.h b/include/vlc_picture_pool.h
index 1ce92ce41278..ec4bf39ea996 100644
--- a/include/vlc_picture_pool.h
+++ b/include/vlc_picture_pool.h
@@ -120,6 +120,17 @@ VLC_API void picture_pool_Release( picture_pool_t * );
  */
 VLC_API picture_t * picture_pool_Get( picture_pool_t * ) VLC_USED;
 
+/**
+ * Obtains a picture from a pool.
+ *
+ * The picture must be released with picture_Release().
+ *
+ * @return a picture or NULL on memory error
+ *
+ * @note This function is thread-safe.
+ */
+VLC_API picture_t *picture_pool_Wait(picture_pool_t *) VLC_USED;
+
 /**
  * Enumerates all pictures in a pool, both free and allocated.
  *
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 147dcd9bf0a3..dd813bc18972 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -311,6 +311,7 @@ picture_pool_New
 picture_pool_NewExtended
 picture_pool_NewFromFormat
 picture_pool_Reserve
+picture_pool_Wait
 picture_Reset
 picture_Setup
 plane_CopyPixels
diff --git a/src/misc/picture_pool.c b/src/misc/picture_pool.c
index bb9c103e1346..f82cb160f84e 100644
--- a/src/misc/picture_pool.c
+++ b/src/misc/picture_pool.c
@@ -40,6 +40,7 @@ struct picture_pool_t {
     int       (*pic_lock)(picture_t *);
     void      (*pic_unlock)(picture_t *);
     vlc_mutex_t lock;
+    vlc_cond_t  wait;
 
     unsigned long long available;
     atomic_ushort      refs;
@@ -52,6 +53,7 @@ static void picture_pool_Destroy(picture_pool_t *pool)
     if (atomic_fetch_sub(&pool->refs, 1) != 1)
         return;
 
+    vlc_cond_destroy(&pool->wait);
     vlc_mutex_destroy(&pool->lock);
     vlc_free(pool);
 }
@@ -80,6 +82,7 @@ static void picture_pool_ReleasePicture(picture_t *clone)
     vlc_mutex_lock(&pool->lock);
     assert(!(pool->available & (1ULL << offset)));
     pool->available |= 1ULL << offset;
+    vlc_cond_signal(&pool->wait);
     vlc_mutex_unlock(&pool->lock);
 
     picture_pool_Destroy(pool);
@@ -122,6 +125,7 @@ picture_pool_t *picture_pool_NewExtended(const picture_pool_configuration_t *cfg
     pool->pic_lock   = cfg->lock;
     pool->pic_unlock = cfg->unlock;
     vlc_mutex_init(&pool->lock);
+    vlc_cond_init(&pool->wait);
     pool->available = (1ULL << cfg->picture_count) - 1;
     atomic_init(&pool->refs,  1);
     pool->picture_count = cfg->picture_count;
@@ -225,6 +229,39 @@ picture_t *picture_pool_Get(picture_pool_t *pool)
     return NULL;
 }
 
+picture_t *picture_pool_Wait(picture_pool_t *pool)
+{
+    unsigned i;
+
+    vlc_mutex_lock(&pool->lock);
+    assert(pool->refs > 0);
+
+    while (pool->available == 0)
+        vlc_cond_wait(&pool->wait, &pool->lock);
+
+    i = ffsll(pool->available);
+    assert(i > 0);
+    pool->available &= ~(1ULL << (i - 1));
+    vlc_mutex_unlock(&pool->lock);
+
+    picture_t *picture = pool->picture[i - 1];
+
+    if (pool->pic_lock != NULL && pool->pic_lock(picture) != 0) {
+        vlc_mutex_lock(&pool->lock);
+        pool->available |= 1ULL << (i - 1);
+        vlc_cond_signal(&pool->wait);
+        vlc_mutex_unlock(&pool->lock);
+        return NULL;
+    }
+
+    picture_t *clone = picture_pool_ClonePicture(pool, i - 1);
+    if (clone != NULL) {
+        assert(clone->p_next == NULL);
+        atomic_fetch_add(&pool->refs, 1);
+    }
+    return clone;
+}
+
 unsigned picture_pool_Reset(picture_pool_t *pool)
 {
     unsigned ret;
diff --git a/src/test/picture_pool.c b/src/test/picture_pool.c
index 2ff3d51563ee..35229cf66bd7 100644
--- a/src/test/picture_pool.c
+++ b/src/test/picture_pool.c
@@ -69,6 +69,14 @@ static void test(bool zombie)
         assert(pics[i]->p[0].p_pixels == plane);
     }
 
+    for (unsigned i = 0; i < PICTURES; i++)
+        picture_Release(pics[i]);
+
+    for (unsigned i = 0; i < PICTURES; i++) {
+        pics[i] = picture_pool_Wait(pool);
+        assert(pics[i] != NULL);
+    }
+
     for (unsigned i = 0; i < PICTURES; i++)
         picture_Release(pics[i]);
 
diff --git a/src/video_output/display.c b/src/video_output/display.c
index 76287cfd7cb6..e9f27fd84175 100644
--- a/src/video_output/display.c
+++ b/src/video_output/display.c
@@ -36,6 +36,7 @@
 #include <vlc_block.h>
 #include <vlc_modules.h>
 #include <vlc_filter.h>
+#include <vlc_picture_pool.h>
 
 #include <libvlc.h>
 
-- 
GitLab