]> git.sesse.net Git - vlc/blob - src/misc/picture_pool.c
Use var_Inherit* instead of var_CreateGet*.
[vlc] / src / misc / picture_pool.c
1 /*****************************************************************************
2  * picture_pool.c : picture pool functions
3  *****************************************************************************
4  * Copyright (C) 2009 the VideoLAN team
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
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 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 General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, 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
37 /*****************************************************************************
38  *
39  *****************************************************************************/
40 struct picture_release_sys_t {
41     /* Saved release */
42     void (*release)(picture_t *);
43     picture_release_sys_t *release_sys;
44
45     /* */
46     int  (*lock)(picture_t *);
47     void (*unlock)(picture_t *);
48
49     /* */
50     int64_t tick;
51 };
52
53 struct picture_pool_t {
54     /* */
55     picture_pool_t *master;
56     int64_t        tick;
57     /* */
58     int            picture_count;
59     picture_t      **picture;
60     bool           *picture_reserved;
61 };
62
63 static void Release(picture_t *);
64 static int  Lock(picture_t *);
65 static void Unlock(picture_t *);
66
67 static picture_pool_t *Create(picture_pool_t *master, int picture_count)
68 {
69     picture_pool_t *pool = calloc(1, sizeof(*pool));
70     if (!pool)
71         return NULL;
72
73     pool->master = master;
74     pool->tick = master ? master->tick : 1;
75     pool->picture_count = picture_count;
76     pool->picture = calloc(pool->picture_count, sizeof(*pool->picture));
77     pool->picture_reserved = calloc(pool->picture_count, sizeof(*pool->picture_reserved));
78     if (!pool->picture || !pool->picture_reserved) {
79         free(pool->picture);
80         free(pool->picture_reserved);
81         free(pool);
82         return NULL;
83     }
84     return pool;
85 }
86
87 picture_pool_t *picture_pool_NewExtended(const picture_pool_configuration_t *cfg)
88 {
89     picture_pool_t *pool = Create(NULL, cfg->picture_count);
90     if (!pool)
91         return NULL;
92
93     for (int i = 0; i < cfg->picture_count; i++) {
94         picture_t *picture = cfg->picture[i];
95
96         /* The pool must be the only owner of the picture */
97         assert(picture->i_refcount == 1);
98
99         /* Install the new release callback */
100         picture_release_sys_t *release_sys = malloc(sizeof(*release_sys));
101         if (!release_sys)
102             abort();
103         release_sys->release     = picture->pf_release;
104         release_sys->release_sys = picture->p_release_sys;
105         release_sys->lock        = cfg->lock;
106         release_sys->unlock      = cfg->unlock;
107         release_sys->tick        = 0;
108
109         /* */
110         picture->i_refcount    = 0;
111         picture->pf_release    = Release;
112         picture->p_release_sys = release_sys;
113
114         /* */
115         pool->picture[i] = picture;
116         pool->picture_reserved[i] = false;
117     }
118     return pool;
119
120 }
121
122 picture_pool_t *picture_pool_New(int picture_count, picture_t *picture[])
123 {
124     picture_pool_configuration_t cfg;
125
126     memset(&cfg, 0, sizeof(cfg));
127     cfg.picture_count = picture_count;
128     cfg.picture       = picture;
129
130     return picture_pool_NewExtended(&cfg);
131 }
132
133 picture_pool_t *picture_pool_NewFromFormat(const video_format_t *fmt, int picture_count)
134 {
135     picture_t *picture[picture_count];
136
137     for (int i = 0; i < picture_count; i++) {
138         picture[i] = picture_NewFromFormat(fmt);
139         if (!picture[i])
140             goto error;
141     }
142     picture_pool_t *pool = picture_pool_New(picture_count, picture);
143     if (!pool)
144         goto error;
145
146     return pool;
147
148 error:
149     for (int i = 0; i < picture_count; i++) {
150         if (!picture[i])
151             break;
152         picture_Release(picture[i]);
153     }
154     return NULL;
155 }
156
157 picture_pool_t *picture_pool_Reserve(picture_pool_t *master, int count)
158 {
159     picture_pool_t *pool = Create(master, count);
160     if (!pool)
161         return NULL;
162
163     int found = 0;
164     for (int i = 0; i < master->picture_count && found < count; i++) {
165         if (master->picture_reserved[i])
166             continue;
167
168         assert(master->picture[i]->i_refcount == 0);
169         master->picture_reserved[i] = true;
170
171         pool->picture[found]          = master->picture[i];
172         pool->picture_reserved[found] = false;
173         found++;
174     }
175     if (found < count) {
176         picture_pool_Delete(pool);
177         return NULL;
178     }
179     return pool;
180 }
181
182 void picture_pool_Delete(picture_pool_t *pool)
183 {
184     for (int i = 0; i < pool->picture_count; i++) {
185         picture_t *picture = pool->picture[i];
186         if (pool->master) {
187             for (int j = 0; j < pool->master->picture_count; j++) {
188                 if (pool->master->picture[j] == picture)
189                     pool->master->picture_reserved[j] = false;
190             }
191         } else {
192             picture_release_sys_t *release_sys = picture->p_release_sys;
193
194             assert(picture->i_refcount == 0);
195             assert(!pool->picture_reserved[i]);
196
197             /* Restore old release callback */
198             picture->i_refcount    = 1;
199             picture->pf_release    = release_sys->release;
200             picture->p_release_sys = release_sys->release_sys;
201
202             picture_Release(picture);
203
204             free(release_sys);
205         }
206     }
207     free(pool->picture_reserved);
208     free(pool->picture);
209     free(pool);
210 }
211
212 picture_t *picture_pool_Get(picture_pool_t *pool)
213 {
214     for (int i = 0; i < pool->picture_count; i++) {
215         if (pool->picture_reserved[i])
216             continue;
217
218         picture_t *picture = pool->picture[i];
219         if (picture->i_refcount > 0)
220             continue;
221
222         if (Lock(picture))
223             continue;
224
225         /* */
226         picture->p_release_sys->tick = pool->tick++;
227         picture_Hold(picture);
228         return picture;
229     }
230     return NULL;
231 }
232
233 void picture_pool_NonEmpty(picture_pool_t *pool, bool reset)
234 {
235     picture_t *old = NULL;
236
237     for (int i = 0; i < pool->picture_count; i++) {
238         if (pool->picture_reserved[i])
239             continue;
240
241         picture_t *picture = pool->picture[i];
242         if (reset) {
243             if (picture->i_refcount > 0)
244                 Unlock(picture);
245             picture->i_refcount = 0;
246         } else if (picture->i_refcount == 0) {
247             return;
248         } else if (!old || picture->p_release_sys->tick < old->p_release_sys->tick) {
249             old = picture;
250         }
251     }
252     if (!reset && old) {
253         if (old->i_refcount > 0)
254             Unlock(old);
255         old->i_refcount = 0;
256     }
257 }
258 int picture_pool_GetSize(picture_pool_t *pool)
259 {
260     return pool->picture_count;
261 }
262
263 static void Release(picture_t *picture)
264 {
265     assert(picture->i_refcount > 0);
266
267     if (--picture->i_refcount > 0)
268         return;
269     Unlock(picture);
270 }
271
272 static int Lock(picture_t *picture)
273 {
274     picture_release_sys_t *release_sys = picture->p_release_sys;
275     if (release_sys->lock)
276         return release_sys->lock(picture);
277     return VLC_SUCCESS;
278 }
279 static void Unlock(picture_t *picture)
280 {
281     picture_release_sys_t *release_sys = picture->p_release_sys;
282     if (release_sys->unlock)
283         release_sys->unlock(picture);
284 }
285