Coverage Report

Created: 2026-06-30 07:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/src/misc/picture_pool.c
Line
Count
Source
1
/*****************************************************************************
2
 * picture_pool.c : picture pool functions
3
 *****************************************************************************
4
 * Copyright (C) 2009 VLC authors and VideoLAN
5
 * Copyright (C) 2009 Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
6
 * Copyright (C) 2013-2015 Rémi Denis-Courmont
7
 *
8
 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
9
 *
10
 * This program is free software; you can redistribute it and/or modify it
11
 * under the terms of the GNU Lesser General Public License as published by
12
 * the Free Software Foundation; either version 2.1 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU Lesser General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General Public License
21
 * along with this program; if not, write to the Free Software Foundation,
22
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23
 *****************************************************************************/
24
25
#ifdef HAVE_CONFIG_H
26
# include "config.h"
27
#endif
28
#include <assert.h>
29
#include <limits.h>
30
#include <stdatomic.h>
31
#include <stdbit.h>
32
#include <stdlib.h>
33
34
#include <vlc_common.h>
35
#include <vlc_threads.h>
36
#include <vlc_picture_pool.h>
37
#include <vlc_atomic.h>
38
#include <vlc_list.h>
39
#include "picture.h"
40
41
#define POOL_MAX 256
42
43
struct picture_pool_t {
44
    vlc_mutex_t lock;
45
    vlc_cond_t  wait;
46
47
    vlc_atomic_rc_t    refs;
48
    bool released;
49
    struct vlc_list inuse_list;
50
    struct vlc_list available_list;
51
};
52
53
static void picture_pool_Destroy(picture_pool_t *pool)
54
0
{
55
0
    if (!vlc_atomic_rc_dec(&pool->refs))
56
0
        return;
57
58
0
    assert(vlc_list_is_empty(&pool->inuse_list));
59
0
    assert(vlc_list_is_empty(&pool->available_list));
60
61
0
    free(pool);
62
0
}
63
64
void picture_pool_Release(picture_pool_t *pool)
65
0
{
66
0
    vlc_mutex_lock(&pool->lock);
67
68
    /* Release pictures from both available and in-use lists */
69
0
    for (size_t i = 0; i < 2; ++i)
70
0
    {
71
0
        struct vlc_list *list = i == 0 ? &pool->available_list : &pool->inuse_list;
72
73
0
        picture_priv_t *priv;
74
0
        vlc_list_foreach(priv, list, pool_node)
75
0
        {
76
0
            assert(priv->pool == pool);
77
0
            vlc_list_remove(&priv->pool_node);
78
0
            picture_Release(&priv->picture);
79
0
        }
80
0
    }
81
    /* Prevent in-use cloned pictures to be added back to lists */
82
0
    pool->released = true;
83
0
    vlc_mutex_unlock(&pool->lock);
84
0
    picture_pool_Destroy(pool);
85
0
}
86
87
static void picture_pool_ReleaseClone(picture_t *clone)
88
0
{
89
0
    picture_priv_t *priv = container_of(clone, picture_priv_t, picture);
90
91
    /* Retrieve the original pic that was cloned */
92
0
    picture_t *original = priv->gc.opaque;
93
0
    picture_priv_t *original_priv = container_of(original, picture_priv_t, picture);
94
95
0
    picture_pool_t *pool = original_priv->pool;
96
0
    assert(pool != NULL);
97
98
0
    vlc_mutex_lock(&pool->lock);
99
100
0
    if (!pool->released)
101
0
    {
102
0
        vlc_list_remove(&original_priv->pool_node);
103
0
        vlc_list_append(&original_priv->pool_node, &pool->available_list);
104
0
        vlc_cond_signal(&pool->wait);
105
0
    }
106
107
0
    vlc_mutex_unlock(&pool->lock);
108
109
0
    picture_Release(original);
110
111
0
    picture_pool_Destroy(pool);
112
0
}
113
114
static picture_t *picture_pool_ClonePicture(picture_pool_t *pool,
115
                                            picture_t *picture)
116
0
{
117
0
    picture_t *clone = picture_InternalClone(picture, picture_pool_ReleaseClone,
118
0
                                             picture);
119
0
    if (clone != NULL) {
120
0
        assert(!picture_HasChainedPics(clone));
121
0
        vlc_atomic_rc_inc(&pool->refs);
122
0
    }
123
0
    return clone;
124
0
}
125
126
static void picture_pool_AppendPic(picture_pool_t *pool, picture_t *pic)
127
0
{
128
0
    picture_priv_t *priv = container_of(pic, picture_priv_t, picture);
129
0
    assert(priv->pool == NULL);
130
0
    vlc_list_append(&priv->pool_node, &pool->available_list);
131
0
    priv->pool = pool;
132
0
}
133
134
static picture_pool_t *
135
picture_pool_NewCommon(void)
136
0
{
137
0
    picture_pool_t *pool = malloc(sizeof(*pool));
138
139
0
    if (unlikely(pool == NULL))
140
0
        return NULL;
141
142
0
    vlc_list_init(&pool->inuse_list);
143
0
    vlc_list_init(&pool->available_list);
144
145
0
    vlc_mutex_init(&pool->lock);
146
0
    vlc_cond_init(&pool->wait);
147
0
    vlc_atomic_rc_init(&pool->refs);
148
0
    pool->released = false;
149
150
0
    return pool;
151
0
}
152
153
picture_pool_t *picture_pool_New(unsigned count, picture_t *const *tab)
154
0
{
155
0
    if (unlikely(count > POOL_MAX))
156
0
        return NULL;
157
158
0
    picture_pool_t *pool = picture_pool_NewCommon();
159
0
    if (unlikely(pool == NULL))
160
0
        return NULL;
161
162
0
    for (unsigned i = 0; i < count; ++i)
163
0
        picture_pool_AppendPic(pool, tab[i]);
164
0
    return pool;
165
0
}
166
167
picture_pool_t *picture_pool_NewFromFormat(const video_format_t *fmt,
168
                                           unsigned count)
169
0
{
170
0
    if (count == 0)
171
0
        vlc_assert_unreachable();
172
0
    if (unlikely(count > POOL_MAX))
173
0
        return NULL;
174
175
0
    picture_pool_t *pool = picture_pool_NewCommon();
176
0
    if (unlikely(pool == NULL))
177
0
        return NULL;
178
179
0
    for (unsigned i = 0; i < count; ++i)
180
0
    {
181
0
        picture_t *pic = picture_NewFromFormat(fmt);
182
0
        if (pic == NULL)
183
0
        {
184
0
            picture_pool_Release(pool);
185
0
            return NULL;
186
0
        }
187
0
        picture_pool_AppendPic(pool, pic);
188
0
    }
189
190
0
    return pool;
191
0
}
192
193
static picture_t *picture_pool_GetAvailableLocked(picture_pool_t *pool)
194
0
{
195
0
    picture_priv_t *priv = vlc_list_first_entry_or_null(&pool->available_list,
196
0
                                                        picture_priv_t,
197
0
                                                        pool_node);
198
0
    assert(priv != NULL);
199
200
0
    assert(priv->pool == pool);
201
202
0
    vlc_list_remove(&priv->pool_node);
203
0
    vlc_list_append(&priv->pool_node, &pool->inuse_list);
204
205
0
    return &priv->picture;
206
0
}
207
208
picture_t *picture_pool_Get(picture_pool_t *pool)
209
0
{
210
211
0
    vlc_mutex_lock(&pool->lock);
212
0
    assert(vlc_atomic_rc_get(&pool->refs) > 0);
213
214
0
    if (vlc_list_is_empty(&pool->available_list))
215
0
    {
216
0
        vlc_mutex_unlock(&pool->lock);
217
0
        return NULL;
218
0
    }
219
220
0
    picture_t *pic = picture_pool_GetAvailableLocked(pool);
221
222
0
    vlc_mutex_unlock(&pool->lock);
223
224
0
    return picture_pool_ClonePicture(pool, pic);
225
0
}
226
227
picture_t *picture_pool_Wait(picture_pool_t *pool)
228
0
{
229
0
    vlc_mutex_lock(&pool->lock);
230
0
    assert(vlc_atomic_rc_get(&pool->refs) > 0);
231
232
0
    while (vlc_list_is_empty(&pool->available_list))
233
0
        vlc_cond_wait(&pool->wait, &pool->lock);
234
235
0
    picture_t *pic = picture_pool_GetAvailableLocked(pool);
236
237
0
    vlc_mutex_unlock(&pool->lock);
238
239
0
    return picture_pool_ClonePicture(pool, pic);
240
0
}