Fix memory leak in video_output on Mac OS X (close #6267)
[vlc/solaris.git] / src / misc / picture_pool.c
blob14db3b65a8fe8c6d6e1bf507d6c226ecb00fdbc9
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 * $Id$
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 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32 #include <assert.h>
34 #include <vlc_common.h>
35 #include <vlc_picture_pool.h>
36 #include <vlc_atomic.h>
38 /*****************************************************************************
40 *****************************************************************************/
41 struct picture_gc_sys_t {
42 /* Saved release */
43 void (*destroy)(picture_t *);
44 void *destroy_sys;
46 /* */
47 int (*lock)(picture_t *);
48 void (*unlock)(picture_t *);
50 /* */
51 int64_t tick;
54 struct picture_pool_t {
55 /* */
56 picture_pool_t *master;
57 int64_t tick;
58 /* */
59 int picture_count;
60 picture_t **picture;
61 bool *picture_reserved;
64 static void Destroy(picture_t *);
65 static int Lock(picture_t *);
66 static void Unlock(picture_t *);
68 static picture_pool_t *Create(picture_pool_t *master, int picture_count)
70 picture_pool_t *pool = calloc(1, sizeof(*pool));
71 if (!pool)
72 return NULL;
74 pool->master = master;
75 pool->tick = master ? master->tick : 1;
76 pool->picture_count = picture_count;
77 pool->picture = calloc(pool->picture_count, sizeof(*pool->picture));
78 pool->picture_reserved = calloc(pool->picture_count, sizeof(*pool->picture_reserved));
79 if (!pool->picture || !pool->picture_reserved) {
80 free(pool->picture);
81 free(pool->picture_reserved);
82 free(pool);
83 return NULL;
85 return pool;
88 picture_pool_t *picture_pool_NewExtended(const picture_pool_configuration_t *cfg)
90 picture_pool_t *pool = Create(NULL, cfg->picture_count);
91 if (!pool)
92 return NULL;
94 for (int i = 0; i < cfg->picture_count; i++) {
95 picture_t *picture = cfg->picture[i];
97 /* The pool must be the only owner of the picture */
98 assert(!picture_IsReferenced(picture));
100 /* Install the new release callback */
101 picture_gc_sys_t *gc_sys = malloc(sizeof(*gc_sys));
102 if (!gc_sys)
103 abort();
104 gc_sys->destroy = picture->gc.pf_destroy;
105 gc_sys->destroy_sys = picture->gc.p_sys;
106 gc_sys->lock = cfg->lock;
107 gc_sys->unlock = cfg->unlock;
108 gc_sys->tick = 0;
110 /* */
111 vlc_atomic_set(&picture->gc.refcount, 0);
112 picture->gc.pf_destroy = Destroy;
113 picture->gc.p_sys = gc_sys;
115 /* */
116 pool->picture[i] = picture;
117 pool->picture_reserved[i] = false;
119 return pool;
123 picture_pool_t *picture_pool_New(int picture_count, picture_t *picture[])
125 picture_pool_configuration_t cfg;
127 memset(&cfg, 0, sizeof(cfg));
128 cfg.picture_count = picture_count;
129 cfg.picture = picture;
131 return picture_pool_NewExtended(&cfg);
134 picture_pool_t *picture_pool_NewFromFormat(const video_format_t *fmt, int picture_count)
136 picture_t *picture[picture_count];
138 for (int i = 0; i < picture_count; i++) {
139 picture[i] = picture_NewFromFormat(fmt);
140 if (!picture[i])
141 goto error;
143 picture_pool_t *pool = picture_pool_New(picture_count, picture);
144 if (!pool)
145 goto error;
147 return pool;
149 error:
150 for (int i = 0; i < picture_count; i++) {
151 if (!picture[i])
152 break;
153 picture_Release(picture[i]);
155 return NULL;
158 picture_pool_t *picture_pool_Reserve(picture_pool_t *master, int count)
160 picture_pool_t *pool = Create(master, count);
161 if (!pool)
162 return NULL;
164 int found = 0;
165 for (int i = 0; i < master->picture_count && found < count; i++) {
166 if (master->picture_reserved[i])
167 continue;
169 assert(vlc_atomic_get(&master->picture[i]->gc.refcount) == 0);
170 master->picture_reserved[i] = true;
172 pool->picture[found] = master->picture[i];
173 pool->picture_reserved[found] = false;
174 found++;
176 if (found < count) {
177 picture_pool_Delete(pool);
178 return NULL;
180 return pool;
183 void picture_pool_Delete(picture_pool_t *pool)
185 for (int i = 0; i < pool->picture_count; i++) {
186 picture_t *picture = pool->picture[i];
187 if (pool->master) {
188 for (int j = 0; j < pool->master->picture_count; j++) {
189 if (pool->master->picture[j] == picture)
190 pool->master->picture_reserved[j] = false;
192 } else {
193 picture_gc_sys_t *gc_sys = picture->gc.p_sys;
195 assert(vlc_atomic_get(&picture->gc.refcount) == 0);
196 assert(!pool->picture_reserved[i]);
198 /* Restore old release callback */
199 vlc_atomic_set(&picture->gc.refcount, 1);
200 picture->gc.pf_destroy = gc_sys->destroy;
201 picture->gc.p_sys = gc_sys->destroy_sys;
203 picture_Release(picture);
205 free(gc_sys);
208 free(pool->picture_reserved);
209 free(pool->picture);
210 free(pool);
213 picture_t *picture_pool_Get(picture_pool_t *pool)
215 for (int i = 0; i < pool->picture_count; i++) {
216 if (pool->picture_reserved[i])
217 continue;
219 picture_t *picture = pool->picture[i];
220 if (vlc_atomic_get(&picture->gc.refcount) > 0)
221 continue;
223 if (Lock(picture))
224 continue;
226 /* */
227 picture->p_next = NULL;
228 picture->gc.p_sys->tick = pool->tick++;
229 picture_Hold(picture);
230 return picture;
232 return NULL;
235 void picture_pool_NonEmpty(picture_pool_t *pool, bool reset)
237 picture_t *old = NULL;
239 for (int i = 0; i < pool->picture_count; i++) {
240 if (pool->picture_reserved[i])
241 continue;
243 picture_t *picture = pool->picture[i];
244 if (reset) {
245 if (vlc_atomic_get(&picture->gc.refcount) > 0)
246 Unlock(picture);
247 vlc_atomic_set(&picture->gc.refcount, 0);
248 } else if (vlc_atomic_get(&picture->gc.refcount) == 0) {
249 return;
250 } else if (!old || picture->gc.p_sys->tick < old->gc.p_sys->tick) {
251 old = picture;
254 if (!reset && old) {
255 if (vlc_atomic_get(&old->gc.refcount) > 0)
256 Unlock(old);
257 vlc_atomic_set(&old->gc.refcount, 0);
260 int picture_pool_GetSize(picture_pool_t *pool)
262 return pool->picture_count;
265 static void Destroy(picture_t *picture)
267 Unlock(picture);
270 static int Lock(picture_t *picture)
272 picture_gc_sys_t *gc_sys = picture->gc.p_sys;
273 if (gc_sys->lock)
274 return gc_sys->lock(picture);
275 return VLC_SUCCESS;
277 static void Unlock(picture_t *picture)
279 picture_gc_sys_t *gc_sys = picture->gc.p_sys;
280 if (gc_sys->unlock)
281 gc_sys->unlock(picture);