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>
8 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_picture_pool.h>
37 /*****************************************************************************
39 *****************************************************************************/
40 struct picture_gc_sys_t {
47 struct picture_pool_t {
50 unsigned picture_count;
53 int (*pic_lock)(picture_t *);
54 void (*pic_unlock)(picture_t *);
59 static void picture_pool_Release(picture_pool_t *pool)
63 vlc_mutex_lock(&pool->lock);
64 assert(pool->refs > 0);
65 destroy = --pool->refs == 0;
66 vlc_mutex_unlock(&pool->lock);
71 for (unsigned i = 0; i < pool->picture_count; i++) {
72 picture_t *picture = pool->picture[i];
73 picture_gc_sys_t *sys = picture->gc.p_sys;
75 picture_Release(sys->picture);
80 vlc_mutex_destroy(&pool->lock);
85 static void picture_pool_ReleasePicture(picture_t *picture)
87 picture_gc_sys_t *sys = picture->gc.p_sys;
88 picture_pool_t *pool = sys->pool;
90 if (pool->pic_unlock != NULL)
91 pool->pic_unlock(picture);
93 vlc_mutex_lock(&pool->lock);
96 vlc_mutex_unlock(&pool->lock);
98 picture_pool_Release(pool);
101 static picture_t *picture_pool_ClonePicture(picture_pool_t *pool,
104 picture_gc_sys_t *sys = malloc(sizeof(*sys));
105 if (unlikely(sys == NULL))
109 sys->picture = picture;
113 picture_resource_t res = {
114 .p_sys = picture->p_sys,
115 .pf_destroy = picture_pool_ReleasePicture,
118 for (int i = 0; i < picture->i_planes; i++) {
119 res.p[i].p_pixels = picture->p[i].p_pixels;
120 res.p[i].i_lines = picture->p[i].i_lines;
121 res.p[i].i_pitch = picture->p[i].i_pitch;
124 picture_t *clone = picture_NewFromResource(&picture->format, &res);
125 if (likely(clone != NULL))
126 clone->gc.p_sys = sys;
133 static picture_pool_t *Create(int picture_count)
135 picture_pool_t *pool = calloc(1, sizeof(*pool));
140 pool->picture_count = picture_count;
141 pool->picture = calloc(pool->picture_count, sizeof(*pool->picture));
142 if (!pool->picture) {
148 vlc_mutex_init(&pool->lock);
152 picture_pool_t *picture_pool_NewExtended(const picture_pool_configuration_t *cfg)
154 picture_pool_t *pool = Create(cfg->picture_count);
158 pool->pic_lock = cfg->lock;
159 pool->pic_unlock = cfg->unlock;
161 for (unsigned i = 0; i < cfg->picture_count; i++) {
162 picture_t *picture = picture_pool_ClonePicture(pool, cfg->picture[i]);
163 if (unlikely(picture == NULL))
166 atomic_init(&picture->gc.refcount, 0);
168 pool->picture[i] = picture;
174 picture_pool_t *picture_pool_New(unsigned count, picture_t *const *tab)
176 picture_pool_configuration_t cfg;
178 memset(&cfg, 0, sizeof(cfg));
179 cfg.picture_count = count;
182 return picture_pool_NewExtended(&cfg);
185 picture_pool_t *picture_pool_NewFromFormat(const video_format_t *fmt,
188 picture_t *picture[count ? count : 1];
191 for (i = 0; i < count; i++) {
192 picture[i] = picture_NewFromFormat(fmt);
193 if (picture[i] == NULL)
197 picture_pool_t *pool = picture_pool_New(count, picture);
205 picture_Release(picture[--i]);
209 picture_pool_t *picture_pool_Reserve(picture_pool_t *master, unsigned count)
211 picture_t *picture[count ? count : 1];
214 for (i = 0; i < count; i++) {
215 picture[i] = picture_pool_Get(master);
216 if (picture[i] == NULL)
220 picture_pool_t *pool = picture_pool_New(count, picture);
224 pool->pic_lock = master->pic_lock;
225 pool->pic_unlock = master->pic_unlock;
230 picture_Release(picture[--i]);
234 void picture_pool_Delete(picture_pool_t *pool)
236 picture_pool_Release(pool);
239 picture_t *picture_pool_Get(picture_pool_t *pool)
241 vlc_mutex_lock(&pool->lock);
242 assert(pool->refs > 0);
244 for (unsigned i = 0; i < pool->picture_count; i++) {
245 picture_t *picture = pool->picture[i];
246 picture_gc_sys_t *sys = picture->gc.p_sys;
255 vlc_mutex_unlock(&pool->lock);
257 if (pool->pic_lock != NULL && pool->pic_lock(picture) != 0) {
258 vlc_mutex_lock(&pool->lock);
261 vlc_mutex_unlock(&pool->lock);
267 assert(atomic_load(&picture->gc.refcount) == 0);
268 atomic_init(&picture->gc.refcount, 1);
269 picture->p_next = NULL;
273 vlc_mutex_unlock(&pool->lock);
277 unsigned picture_pool_Reset(picture_pool_t *pool)
281 vlc_mutex_lock(&pool->lock);
282 assert(pool->refs > 0);
284 for (unsigned i = 0; i < pool->picture_count; i++) {
285 picture_t *picture = pool->picture[i];
286 picture_gc_sys_t *sys = picture->gc.p_sys;
289 vlc_mutex_unlock(&pool->lock);
290 picture_Release(picture);
295 vlc_mutex_unlock(&pool->lock);
300 void picture_pool_NonEmpty(picture_pool_t *pool)
302 picture_t *oldest = NULL;
305 vlc_mutex_lock(&pool->lock);
306 assert(pool->refs > 0);
308 for (unsigned i = 0; i < pool->picture_count; i++) {
309 picture_t *picture = pool->picture[i];
310 picture_gc_sys_t *sys = picture->gc.p_sys;
313 vlc_mutex_unlock(&pool->lock);
314 return; /* Nothing to do */
317 if (picture->gc.p_sys->tick < tick) {
319 tick = picture->gc.p_sys->tick;
323 if (oldest != NULL) {
324 while (oldest->gc.p_sys->in_use) {
325 vlc_mutex_unlock(&pool->lock);
326 picture_Release(oldest);
327 vlc_mutex_lock(&pool->lock);
331 vlc_mutex_unlock(&pool->lock);
334 int picture_pool_GetSize(picture_pool_t *pool)
336 return pool->picture_count;