]> git.sesse.net Git - vlc/blob - src/misc/picture_pool.c
8719a374118b2f7590ecacad4b1194cdab96f7d3
[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     int64_t   tick;
56     /* */
57     int       picture_count;
58     picture_t **picture;
59 };
60
61 static void PicturePoolPictureRelease(picture_t *);
62
63 picture_pool_t *picture_pool_NewExtended(const picture_pool_configuration_t *cfg)
64 {
65     picture_pool_t *pool = calloc(1, sizeof(*pool));
66     if (!pool)
67         return NULL;
68
69     pool->tick = 1;
70     pool->picture_count = cfg->picture_count;
71     pool->picture = calloc(pool->picture_count, sizeof(*pool->picture));
72     if (!pool->picture) {
73         free(pool);
74         return NULL;
75     }
76
77     for (int i = 0; i < cfg->picture_count; i++) {
78         picture_t *picture = cfg->picture[i];
79
80         /* The pool must be the only owner of the picture */
81         assert(picture->i_refcount == 1);
82
83         /* Install the new release callback */
84         picture_release_sys_t *release_sys = malloc(sizeof(*release_sys));
85         if (!release_sys)
86             abort();
87         release_sys->release     = picture->pf_release;
88         release_sys->release_sys = picture->p_release_sys;
89         release_sys->lock        = cfg->lock;
90         release_sys->unlock      = cfg->unlock;
91         release_sys->tick        = 0;
92
93         /* */
94         picture->i_refcount    = 0;
95         picture->pf_release    = PicturePoolPictureRelease;
96         picture->p_release_sys = release_sys;
97
98         /* */
99         pool->picture[i] = picture;
100     }
101     return pool;
102
103 }
104
105 picture_pool_t *picture_pool_New(int picture_count, picture_t *picture[])
106 {
107     picture_pool_configuration_t cfg;
108
109     memset(&cfg, 0, sizeof(cfg));
110     cfg.picture_count = picture_count;
111     cfg.picture       = picture;
112
113     return picture_pool_NewExtended(&cfg);
114 }
115
116 picture_pool_t *picture_pool_NewFromFormat(const video_format_t *fmt, int picture_count)
117 {
118     picture_t *picture[picture_count];
119
120     for (int i = 0; i < picture_count; i++) {
121         picture[i] = picture_NewFromFormat(fmt);
122         if (!picture[i])
123             goto error;
124     }
125     picture_pool_t *pool = picture_pool_New(picture_count, picture);
126     if (!pool)
127         goto error;
128
129     return pool;
130
131 error:
132     for (int i = 0; i < picture_count; i++) {
133         if (!picture[i])
134             break;
135         picture_Release(picture[i]);
136     }
137     return NULL;
138 }
139
140 void picture_pool_Delete(picture_pool_t *pool)
141 {
142     for (int i = 0; i < pool->picture_count; i++) {
143         picture_t *picture = pool->picture[i];
144         picture_release_sys_t *release_sys = picture->p_release_sys;
145
146         assert(picture->i_refcount == 0);
147
148         /* Restore old release callback */
149         picture->i_refcount    = 1;
150         picture->pf_release    = release_sys->release;
151         picture->p_release_sys = release_sys->release_sys;
152
153         picture_Release(picture);
154
155         free(release_sys);
156     }
157     free(pool->picture);
158     free(pool);
159 }
160
161 picture_t *picture_pool_Get(picture_pool_t *pool)
162 {
163     for (int i = 0; i < pool->picture_count; i++) {
164         picture_t *picture = pool->picture[i];
165         if (picture->i_refcount > 0)
166             continue;
167
168         picture_release_sys_t *release_sys = picture->p_release_sys;
169         if (release_sys->lock && release_sys->lock(picture))
170             continue;
171
172         /* */
173         picture->p_release_sys->tick = pool->tick++;
174         picture_Hold(picture);
175         return picture;
176     }
177     return NULL;
178 }
179
180 void picture_pool_NonEmpty(picture_pool_t *pool, bool reset)
181 {
182     picture_t *old = NULL;
183
184     for (int i = 0; i < pool->picture_count; i++) {
185         picture_t *picture = pool->picture[i];
186
187         if (reset) {
188             /* TODO pf_unlock */
189             picture->i_refcount = 0;
190         } else if (picture->i_refcount == 0) {
191             return;
192         } else if (!old || picture->p_release_sys->tick < old->p_release_sys->tick) {
193             old = picture;
194         }
195     }
196     if (!reset && old) {
197         /* TODO pf_unlock */
198         old->i_refcount = 0;
199     }
200 }
201
202 static void PicturePoolPictureRelease(picture_t *picture)
203 {
204     assert(picture->i_refcount > 0);
205
206     if (--picture->i_refcount > 0)
207         return;
208
209     picture_release_sys_t *release_sys = picture->p_release_sys;
210     if (release_sys->unlock)
211         release_sys->unlock(picture);
212 }
213