block.c: Remove a warning about unused argument.
[vlc.git] / src / misc / block.c
1 /*****************************************************************************
2  * block.c: Data blocks management functions
3  *****************************************************************************
4  * Copyright (C) 2003-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc/vlc.h>
32 #include "vlc_block.h"
33
34 /*****************************************************************************
35  * Block functions.
36  *****************************************************************************/
37 /* private */
38 struct block_sys_t
39 {
40     block_t     self;
41     size_t      i_allocated_buffer;
42     uint8_t     p_allocated_buffer[0];
43 };
44
45 #ifndef NDEBUG
46 static void BlockNoRelease( block_t *b )
47 {
48     fprintf( stderr, "block %p has no release callback! This is a bug!\n", b );
49     abort();
50 }
51 #endif
52
53 void block_Init( block_t *restrict b, void *buf, size_t size )
54 {
55     /* Fill all fields to their default */
56     b->p_next = b->p_prev = NULL;
57     b->i_flags = 0;
58     b->i_pts = b->i_dts = b->i_length = 0;
59     b->i_rate = 0;
60     b->p_buffer = buf;
61     b->i_buffer = size;
62 #ifndef NDEBUG
63     b->pf_release = BlockNoRelease;
64 #endif
65 }
66
67 static void BlockRelease( block_t *p_block )
68 {
69     free( p_block );
70 }
71
72 #define BLOCK_PADDING_SIZE 32
73
74 block_t *block_Alloc( size_t i_size )
75 {
76     /* We do only one malloc
77      * TODO bench if doing 2 malloc but keeping a pool of buffer is better
78      * 16 -> align on 16
79      * 2 * BLOCK_PADDING_SIZE -> pre + post padding
80      */
81     const size_t i_alloc = i_size + 2 * BLOCK_PADDING_SIZE + 16;
82     block_sys_t *p_sys = malloc( sizeof( *p_sys ) + i_alloc );
83
84     if( p_sys == NULL )
85         return NULL;
86
87     /* Fill opaque data */
88     p_sys->i_allocated_buffer = i_alloc;
89
90     block_Init( &p_sys->self, p_sys->p_allocated_buffer + BLOCK_PADDING_SIZE
91                 + 16 - ((uintptr_t)p_sys->p_allocated_buffer % 16 ), i_size );
92     p_sys->self.pf_release    = BlockRelease;
93
94     return &p_sys->self;
95 }
96
97 block_t *block_Realloc( block_t *p_block, ssize_t i_prebody, size_t i_body )
98 {
99     block_sys_t *p_sys = (block_sys_t *)p_block;
100     ssize_t i_buffer_size;
101
102     if( p_block->pf_release != BlockRelease )
103     {
104         /* Special case when pf_release if overloaded
105          * TODO if used one day, them implement it in a smarter way */
106         block_t *p_dup = block_Duplicate( p_block );
107         block_Release( p_block );
108         if( !p_dup )
109             return NULL;
110
111         p_block = p_dup;
112     }
113
114     i_buffer_size = i_prebody + i_body;
115
116     if( i_buffer_size <= 0 )
117     {
118         block_Release( p_block );
119         return NULL;
120     }
121
122     if( p_block->p_buffer - i_prebody > p_sys->p_allocated_buffer &&
123         p_block->p_buffer - i_prebody < p_sys->p_allocated_buffer +
124         p_sys->i_allocated_buffer )
125     {
126         p_block->p_buffer -= i_prebody;
127         p_block->i_buffer += i_prebody;
128         i_prebody = 0;
129     }
130     if( p_block->p_buffer + i_body < p_sys->p_allocated_buffer +
131         p_sys->i_allocated_buffer )
132     {
133         p_block->i_buffer = i_buffer_size;
134         i_body = 0;
135     }
136
137     if( i_body > 0 || i_prebody > 0 )
138     {
139         block_t *p_rea = block_New( NULL, i_buffer_size );
140
141         if( p_rea )
142         {
143             p_rea->i_dts     = p_block->i_dts;
144             p_rea->i_pts     = p_block->i_pts;
145             p_rea->i_flags   = p_block->i_flags;
146             p_rea->i_length  = p_block->i_length;
147             p_rea->i_rate    = p_block->i_rate;
148             p_rea->i_samples = p_block->i_samples;
149
150             memcpy( p_rea->p_buffer + i_prebody, p_block->p_buffer,
151                     __MIN( p_block->i_buffer, p_rea->i_buffer - i_prebody ) );
152         }
153
154         block_Release( p_block );
155
156         return p_rea;
157     }
158
159     return p_block;
160 }
161
162 #ifdef HAVE_MMAP
163 # include <sys/mman.h>
164
165 typedef struct block_mmap_t
166 {
167     block_t     self;
168     void       *base_addr;
169     size_t      length;
170 } block_mmap_t;
171
172 static void block_mmap_Release (block_t *block)
173 {
174     block_mmap_t *p_sys = (block_mmap_t *)block;
175
176     munmap (p_sys->base_addr, p_sys->length);
177     free (p_sys);
178 }
179
180 block_t *block_mmap_Alloc (void *addr, size_t length)
181 {
182     if (addr == MAP_FAILED)
183         return NULL;
184
185     block_mmap_t *block = malloc (sizeof (*block));
186     if (block == NULL)
187     {
188         munmap (addr, length);
189         return NULL;
190     }
191
192     block_Init (&block->self, (uint8_t *)addr, length);
193     block->self.pf_release = block_mmap_Release;
194     block->base_addr = addr;
195     block->length = length;
196     return &block->self;
197 }
198 #endif
199
200 /*****************************************************************************
201  * block_fifo_t management
202  *****************************************************************************/
203 struct block_fifo_t
204 {
205     vlc_mutex_t         lock;                         /* fifo data lock */
206     vlc_cond_t          wait;         /* fifo data conditional variable */
207
208     block_t             *p_first;
209     block_t             **pp_last;
210     size_t              i_depth;
211     size_t              i_size;
212     vlc_bool_t          b_force_wake;
213 };
214
215 block_fifo_t *__block_FifoNew( vlc_object_t *p_obj )
216 {
217     (void)p_obj;
218
219     block_fifo_t *p_fifo;
220
221     p_fifo = malloc( sizeof( block_fifo_t ) );
222     if( !p_fifo ) return NULL;
223     vlc_mutex_init( p_obj, &p_fifo->lock );
224     vlc_cond_init( p_obj, &p_fifo->wait );
225     p_fifo->p_first = NULL;
226     p_fifo->pp_last = &p_fifo->p_first;
227     p_fifo->i_depth = p_fifo->i_size = 0;
228     p_fifo->b_force_wake = VLC_FALSE;
229
230     return p_fifo;
231 }
232
233 void block_FifoRelease( block_fifo_t *p_fifo )
234 {
235     block_FifoEmpty( p_fifo );
236     vlc_cond_destroy( &p_fifo->wait );
237     vlc_mutex_destroy( &p_fifo->lock );
238     free( p_fifo );
239 }
240
241 void block_FifoEmpty( block_fifo_t *p_fifo )
242 {
243     block_t *b;
244
245     vlc_mutex_lock( &p_fifo->lock );
246     for( b = p_fifo->p_first; b != NULL; )
247     {
248         block_t *p_next;
249
250         p_next = b->p_next;
251         block_Release( b );
252         b = p_next;
253     }
254
255     p_fifo->i_depth = p_fifo->i_size = 0;
256     p_fifo->p_first = NULL;
257     p_fifo->pp_last = &p_fifo->p_first;
258     vlc_mutex_unlock( &p_fifo->lock );
259 }
260
261 size_t block_FifoPut( block_fifo_t *p_fifo, block_t *p_block )
262 {
263     size_t i_size = 0;
264     vlc_mutex_lock( &p_fifo->lock );
265
266     do
267     {
268         i_size += p_block->i_buffer;
269
270         *p_fifo->pp_last = p_block;
271         p_fifo->pp_last = &p_block->p_next;
272         p_fifo->i_depth++;
273         p_fifo->i_size += p_block->i_buffer;
274
275         p_block = p_block->p_next;
276
277     } while( p_block );
278
279     /* warn there is data in this fifo */
280     vlc_cond_signal( &p_fifo->wait );
281     vlc_mutex_unlock( &p_fifo->lock );
282
283     return i_size;
284 }
285
286 void block_FifoWake( block_fifo_t *p_fifo )
287 {
288     vlc_mutex_lock( &p_fifo->lock );
289     if( p_fifo->p_first == NULL )
290         p_fifo->b_force_wake = VLC_TRUE;
291     vlc_cond_signal( &p_fifo->wait );
292     vlc_mutex_unlock( &p_fifo->lock );
293 }
294
295 block_t *block_FifoGet( block_fifo_t *p_fifo )
296 {
297     block_t *b;
298
299     vlc_mutex_lock( &p_fifo->lock );
300
301     /* Remember vlc_cond_wait() may cause spurious wakeups
302      * (on both Win32 and POSIX) */
303     while( ( p_fifo->p_first == NULL ) && !p_fifo->b_force_wake )
304     {
305         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
306     }
307
308     b = p_fifo->p_first;
309
310     p_fifo->b_force_wake = VLC_FALSE;
311     if( b == NULL )
312     {
313         /* Forced wakeup */
314         vlc_mutex_unlock( &p_fifo->lock );
315         return NULL;
316     }
317
318     p_fifo->p_first = b->p_next;
319     p_fifo->i_depth--;
320     p_fifo->i_size -= b->i_buffer;
321
322     if( p_fifo->p_first == NULL )
323     {
324         p_fifo->pp_last = &p_fifo->p_first;
325     }
326
327     vlc_mutex_unlock( &p_fifo->lock );
328
329     b->p_next = NULL;
330     return b;
331 }
332
333 block_t *block_FifoShow( block_fifo_t *p_fifo )
334 {
335     block_t *b;
336
337     vlc_mutex_lock( &p_fifo->lock );
338
339     if( p_fifo->p_first == NULL )
340     {
341         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
342     }
343
344     b = p_fifo->p_first;
345
346     vlc_mutex_unlock( &p_fifo->lock );
347
348     return( b );
349 }
350
351 size_t block_FifoSize( const block_fifo_t *p_fifo )
352 {
353     return p_fifo->i_size;
354 }
355
356 size_t block_FifoCount( const block_fifo_t *p_fifo )
357 {
358     return p_fifo->i_depth;
359 }