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