]> git.sesse.net Git - vlc/blob - src/misc/picture_pool.c
Revert "aout: make log message to be debug as there isn't any real error if no filter...
[vlc] / src / misc / picture_pool.c
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$
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 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32 #include <assert.h>
33
34 #include <vlc_common.h>
35 #include <vlc_picture_pool.h>
36 #include <vlc_atomic.h>
37
38 /*****************************************************************************
39  *
40  *****************************************************************************/
41 struct picture_gc_sys_t {
42     /* Saved release */
43     void (*destroy)(picture_t *);
44     void *destroy_sys;
45
46     /* */
47     int  (*lock)(picture_t *);
48     void (*unlock)(picture_t *);
49
50     /* */
51     int64_t tick;
52 };
53
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;
62 };
63
64 static void Destroy(picture_t *);
65 static int  Lock(picture_t *);
66 static void Unlock(picture_t *);
67
68 static picture_pool_t *Create(picture_pool_t *master, int picture_count)
69 {
70     picture_pool_t *pool = calloc(1, sizeof(*pool));
71     if (!pool)
72         return NULL;
73
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;
84     }
85     return pool;
86 }
87
88 picture_pool_t *picture_pool_NewExtended(const picture_pool_configuration_t *cfg)
89 {
90     picture_pool_t *pool = Create(NULL, cfg->picture_count);
91     if (!pool)
92         return NULL;
93
94     for (int i = 0; i < cfg->picture_count; i++) {
95         picture_t *picture = cfg->picture[i];
96
97         /* The pool must be the only owner of the picture */
98         assert(!picture_IsReferenced(picture));
99
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;
109
110         /* */
111         vlc_atomic_set(&picture->gc.refcount, 0);
112         picture->gc.pf_destroy = Destroy;
113         picture->gc.p_sys      = gc_sys;
114
115         /* */
116         pool->picture[i] = picture;
117         pool->picture_reserved[i] = false;
118     }
119     return pool;
120
121 }
122
123 picture_pool_t *picture_pool_New(int picture_count, picture_t *picture[])
124 {
125     picture_pool_configuration_t cfg;
126
127     memset(&cfg, 0, sizeof(cfg));
128     cfg.picture_count = picture_count;
129     cfg.picture       = picture;
130
131     return picture_pool_NewExtended(&cfg);
132 }
133
134 picture_pool_t *picture_pool_NewFromFormat(const video_format_t *fmt, int picture_count)
135 {
136     picture_t *picture[picture_count];
137
138     for (int i = 0; i < picture_count; i++) {
139         picture[i] = picture_NewFromFormat(fmt);
140         if (!picture[i])
141             goto error;
142     }
143     picture_pool_t *pool = picture_pool_New(picture_count, picture);
144     if (!pool)
145         goto error;
146
147     return pool;
148
149 error:
150     for (int i = 0; i < picture_count; i++) {
151         if (!picture[i])
152             break;
153         picture_Release(picture[i]);
154     }
155     return NULL;
156 }
157
158 picture_pool_t *picture_pool_Reserve(picture_pool_t *master, int count)
159 {
160     picture_pool_t *pool = Create(master, count);
161     if (!pool)
162         return NULL;
163
164     int found = 0;
165     for (int i = 0; i < master->picture_count && found < count; i++) {
166         if (master->picture_reserved[i])
167             continue;
168
169         assert(vlc_atomic_get(&master->picture[i]->gc.refcount) == 0);
170         master->picture_reserved[i] = true;
171
172         pool->picture[found]          = master->picture[i];
173         pool->picture_reserved[found] = false;
174         found++;
175     }
176     if (found < count) {
177         picture_pool_Delete(pool);
178         return NULL;
179     }
180     return pool;
181 }
182
183 void picture_pool_Delete(picture_pool_t *pool)
184 {
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;
191             }
192         } else {
193             picture_gc_sys_t *gc_sys = picture->gc.p_sys;
194
195             assert(vlc_atomic_get(&picture->gc.refcount) == 0);
196             assert(!pool->picture_reserved[i]);
197
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;
202
203             picture_Release(picture);
204
205             free(gc_sys);
206         }
207     }
208     free(pool->picture_reserved);
209     free(pool->picture);
210     free(pool);
211 }
212
213 picture_t *picture_pool_Get(picture_pool_t *pool)
214 {
215     for (int i = 0; i < pool->picture_count; i++) {
216         if (pool->picture_reserved[i])
217             continue;
218
219         picture_t *picture = pool->picture[i];
220         if (vlc_atomic_get(&picture->gc.refcount) > 0)
221             continue;
222
223         if (Lock(picture))
224             continue;
225
226         /* */
227         picture->p_next = NULL;
228         picture->gc.p_sys->tick = pool->tick++;
229         picture_Hold(picture);
230         return picture;
231     }
232     return NULL;
233 }
234
235 void picture_pool_NonEmpty(picture_pool_t *pool, bool reset)
236 {
237     picture_t *old = NULL;
238
239     for (int i = 0; i < pool->picture_count; i++) {
240         if (pool->picture_reserved[i])
241             continue;
242
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;
252         }
253     }
254     if (!reset && old) {
255         if (vlc_atomic_get(&old->gc.refcount) > 0)
256             Unlock(old);
257         vlc_atomic_set(&old->gc.refcount, 0);
258     }
259 }
260 int picture_pool_GetSize(picture_pool_t *pool)
261 {
262     return pool->picture_count;
263 }
264
265 static void Destroy(picture_t *picture)
266 {
267     Unlock(picture);
268 }
269
270 static int Lock(picture_t *picture)
271 {
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;
276 }
277 static void Unlock(picture_t *picture)
278 {
279     picture_gc_sys_t *gc_sys = picture->gc.p_sys;
280     if (gc_sys->unlock)
281         gc_sys->unlock(picture);
282 }
283