* configure.ac : added --enable-goom and --with-goom-tree. Btw, I use a
[vlc.git] / src / misc / block.c
1 /*****************************************************************************
2  * block.c
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: block.c,v 1.1 2003/08/23 22:49:50 fenrir Exp $
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28 #include <stdarg.h>
29
30 #include <vlc/vlc.h>
31 #include "vlc_block.h"
32
33 /* private */
34 struct block_sys_t
35 {
36     vlc_mutex_t lock;
37
38     uint8_t     *p_allocated_buffer;
39     int         i_allocated_buffer;
40
41     vlc_bool_t  b_modify;       /* has it be put in modify state */
42     int         i_duplicated;   /* how many times it has been duplicated (only content) */
43
44 };
45
46 static void BlockRelease( block_t *p_block )
47 {
48     vlc_mutex_lock( &p_block->p_sys->lock );
49
50     p_block->p_sys->i_duplicated--;
51     if( p_block->p_sys->i_duplicated < 0 )
52     {
53         vlc_mutex_unlock( &p_block->p_sys->lock );
54         free( p_block->p_sys->p_allocated_buffer );
55         free( p_block->p_sys );
56         free( p_block );
57
58         return;
59     }
60
61     vlc_mutex_unlock( &p_block->p_sys->lock );
62     free( p_block );
63 }
64
65 static block_t *__BlockDupContent( block_t *p_block )
66 {
67     block_t *p_dup;
68
69     p_dup = block_New( p_block->p_manager, p_block->i_buffer );
70     memcpy( p_dup->p_buffer, p_block->p_buffer, p_block->i_buffer );
71     p_dup->b_frame_display = p_block->b_frame_display;
72     p_dup->b_frame_start   = p_block->b_frame_start;
73     p_dup->i_pts           = p_block->i_pts;
74     p_dup->i_dts           = p_block->i_dts;
75
76     return p_dup;
77 }
78
79 static block_t *BlockModify( block_t *p_block, vlc_bool_t b_will_modify )
80 {
81     block_t *p_mod = p_block;   /* by default */
82
83     vlc_mutex_lock( &p_block->p_sys->lock );
84
85     if( p_block->p_sys->b_modify == b_will_modify )
86     {
87         vlc_mutex_unlock( &p_block->p_sys->lock );
88         return p_block;
89     }
90
91     if( p_block->p_sys->i_duplicated == 0 )
92     {
93         p_block->p_sys->b_modify = b_will_modify;
94         vlc_mutex_unlock( &p_block->p_sys->lock );
95         return p_block;
96     }
97
98     /* FIXME we could avoid that
99      * we just need to create a new p_sys with new mem FIXME */
100     p_mod = __BlockDupContent( p_block );
101     vlc_mutex_unlock( &p_block->p_sys->lock );
102
103     BlockRelease( p_block );
104
105     return p_mod;
106 }
107 static block_t *BlockDuplicate( block_t *p_block )
108 {
109     block_t *p_dup;
110
111     vlc_mutex_lock( &p_block->p_sys->lock );
112     if( !p_block->p_sys->b_modify )
113     {
114         p_block->p_sys->i_duplicated++;
115         vlc_mutex_unlock( &p_block->p_sys->lock );
116         p_dup = block_NewEmpty();
117         memcpy( p_dup, p_block, sizeof( block_t ) );
118         p_dup->p_next = NULL;
119         return p_dup;
120     }
121     p_dup = __BlockDupContent( p_block );
122     vlc_mutex_unlock( &p_block->p_sys->lock );
123
124     return p_dup;
125 }
126
127 static block_t *BlockRealloc( block_t *p_block, int i_prebody, int i_body )
128 {
129
130     vlc_mutex_lock( &p_block->p_sys->lock );
131     if( i_prebody < 0 ||
132         ( p_block->p_buffer - i_prebody > p_block->p_sys->p_allocated_buffer ) )
133     {
134         p_block->p_buffer -= i_prebody;
135         p_block->i_buffer += i_prebody;
136         i_prebody = 0;
137     }
138     if( i_body < 0 ||
139         ( p_block->p_buffer + i_body < p_block->p_sys->p_allocated_buffer + p_block->p_sys->i_allocated_buffer ) )
140     {
141         p_block->i_buffer = i_body;
142         i_body = 0;
143     }
144     vlc_mutex_unlock( &p_block->p_sys->lock );
145
146     if( i_prebody > 0 )
147     {
148         block_t *p_rea = block_New( p_block->p_manager, i_prebody + i_body );
149
150         memcpy( &p_rea->p_buffer[i_prebody], p_block->p_buffer, p_block->i_buffer );
151
152         return p_rea;
153     }
154
155     if( i_body > 0 )
156     {
157         int i_start;
158         block_t *p_rea = BlockModify( p_block, VLC_TRUE );
159
160         i_start = p_rea->p_buffer - p_rea->p_sys->p_allocated_buffer;
161
162         p_rea->p_sys->i_allocated_buffer += i_body - p_rea->i_buffer;
163         p_rea->p_sys->p_allocated_buffer = realloc( p_rea->p_sys->p_allocated_buffer, p_rea->p_sys->i_allocated_buffer );
164
165         p_rea->p_buffer = &p_rea->p_sys->p_allocated_buffer[i_start];
166         p_rea->i_buffer = i_body;
167
168         return p_rea;
169     }
170
171     return p_block;
172 }
173 /*****************************************************************************
174  * Standard block management
175  *
176  *****************************************************************************/
177 /* to be used by other block managment */
178 block_t *block_NewEmpty( void )
179 {
180     block_t *p_block;
181
182     p_block = malloc( sizeof( block_t ) );
183     p_block->p_next         = NULL;
184     p_block->b_frame_display= VLC_TRUE;
185     p_block->b_frame_start  = VLC_FALSE;
186     p_block->i_pts          = 0;
187     p_block->i_dts          = 0;
188
189     p_block->i_buffer       = 0;
190     p_block->p_buffer       = NULL;
191
192     p_block->pf_release     = NULL;
193     p_block->pf_duplicate   = NULL;
194     p_block->pf_modify      = NULL;
195     p_block->pf_realloc     = NULL;
196
197     p_block->p_sys = NULL;
198     return p_block;
199 }
200
201 block_t *__block_New( vlc_object_t *p_obj, int i_size )
202 {
203     block_t     *p_block;
204     block_sys_t *p_sys;
205
206
207     p_block = block_NewEmpty();
208
209     p_block->i_buffer       = i_size;
210     if( i_size > 0 )
211     {
212         p_block->p_buffer   = malloc( i_size );
213     }
214
215     p_block->pf_release     = BlockRelease;
216     p_block->pf_duplicate   = BlockDuplicate;
217     p_block->pf_modify      = BlockModify;
218     p_block->pf_realloc     = BlockRealloc;
219
220     /* that should be ok (no comunication between multiple p_vlc) */
221     p_block->p_manager      = p_obj->p_vlc;
222
223     p_block->p_sys = p_sys = malloc( sizeof( block_sys_t ) );
224     vlc_mutex_init( p_obj, &p_sys->lock );
225     p_sys->p_allocated_buffer = p_block->p_buffer;
226     p_sys->i_allocated_buffer = p_block->i_buffer;
227     p_sys->i_duplicated = 0;
228     p_sys->b_modify = VLC_TRUE;
229
230     return p_block;
231 }
232
233 void    block_ChainAppend( block_t **pp_list, block_t *p_block )
234 {
235
236     if( *pp_list == NULL )
237     {
238         *pp_list = p_block;
239     }
240     else
241     {
242         block_t *p = *pp_list;
243
244         while( p->p_next )
245         {
246             p = p->p_next;
247         }
248         p->p_next = p_block;
249     }
250 }
251
252 void    block_ChainRelease( block_t *p_block )
253 {
254     while( p_block )
255     {
256         block_t *p_next;
257         p_next = p_block->p_next;
258         p_block->pf_release( p_block );
259         p_block = p_next;
260     }
261 }
262
263 int block_ChainExtract( block_t *p_list, void *p_data, int i_max )
264 {
265     block_t *b;
266     int     i_total = 0;
267     uint8_t *p = p_data;
268
269     for( b = p_list; b != NULL; b = b->p_next )
270     {
271         int i_copy;
272
273         i_copy = __MIN( i_max, b->i_buffer );
274         if( i_copy > 0 )
275         {
276             memcpy( p, b->p_buffer, i_copy );
277             i_max   -= i_copy;
278             i_total += i_copy;
279             p       += i_copy;
280
281             if( i_max == 0 )
282             {
283                 return i_total;
284             }
285         }
286     }
287     return i_total;
288 }
289
290 block_t *block_ChainGather( block_t *p_list )
291 {
292     int     i_total = 0;
293     block_t *b, *g;
294
295     if( p_list->p_next == NULL )
296     {
297         /* only one, so no need */
298         return p_list;
299     }
300
301     for( b = p_list; b != NULL; b = b->p_next )
302     {
303         i_total += b->i_buffer;
304     }
305
306     g = block_New( p_list->p_manager, i_total );
307     block_ChainExtract( p_list, g->p_buffer, g->i_buffer );
308
309     g->b_frame_display = p_list->b_frame_display;
310     g->b_frame_start   = p_list->b_frame_start;
311     g->i_pts           = p_list->i_pts;
312     g->i_dts           = p_list->i_dts;
313
314     /* free p_list */
315     block_ChainRelease( p_list );
316     return g;
317 }
318
319
320 /*****************************************************************************
321  * block_fifo_t managment
322  *****************************************************************************/
323 block_fifo_t * __block_FifoNew  ( vlc_object_t *p_obj )
324 {
325     block_fifo_t *p_fifo;
326
327     p_fifo = malloc( sizeof( vlc_object_t ) );
328     vlc_mutex_init( p_obj, &p_fifo->lock );
329     vlc_cond_init( p_obj, &p_fifo->wait );
330     p_fifo->i_depth = 0;
331     p_fifo->p_first = NULL;
332     p_fifo->pp_last = &p_fifo->p_first;
333
334     return p_fifo;
335 }
336
337 void           block_FifoRelease( block_fifo_t *p_fifo )
338 {
339     block_FifoEmpty( p_fifo );
340     vlc_cond_destroy( &p_fifo->wait );
341     vlc_mutex_destroy( &p_fifo->lock );
342     free( p_fifo );
343 }
344
345 void            block_FifoEmpty( block_fifo_t *p_fifo )
346 {
347     block_t *b;
348
349     vlc_mutex_lock( &p_fifo->lock );
350     for( b = p_fifo->p_first; b != NULL; )
351     {
352         block_t *p_next;
353
354         p_next = b->p_next;
355         block_Release( b );
356         b = p_next;
357     }
358
359     p_fifo->i_depth = 0;
360     p_fifo->p_first = NULL;
361     p_fifo->pp_last = &p_fifo->p_first;
362     vlc_mutex_unlock( &p_fifo->lock );
363 }
364
365 int           block_FifoPut    ( block_fifo_t *p_fifo, block_t *p_block )
366 {
367     int i_size = 0;
368     vlc_mutex_lock( &p_fifo->lock );
369
370     do
371     {
372         i_size += p_block->i_buffer;
373
374         *p_fifo->pp_last = p_block;
375         p_fifo->pp_last = &p_block->p_next;
376         p_fifo->i_depth++;
377
378         p_block = p_block->p_next;
379
380     } while( p_block );
381
382     /* warm there is data in this fifo */
383     vlc_cond_signal( &p_fifo->wait );
384     vlc_mutex_unlock( &p_fifo->lock );
385
386     return i_size;
387 }
388
389 block_t *      block_FifoGet    ( block_fifo_t *p_fifo )
390 {
391     block_t *b;
392
393     vlc_mutex_lock( &p_fifo->lock );
394
395     if( p_fifo->p_first == NULL )
396     {
397         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
398     }
399
400     b = p_fifo->p_first;
401
402     p_fifo->p_first = b->p_next;
403     p_fifo->i_depth--;
404
405     if( p_fifo->p_first == NULL )
406     {
407         p_fifo->pp_last = &p_fifo->p_first;
408     }
409
410     vlc_mutex_unlock( &p_fifo->lock );
411
412     b->p_next = NULL;
413     return( b );
414 }
415
416 block_t *      block_FifoShow   ( block_fifo_t *p_fifo )
417 {
418     block_t *b;
419
420     vlc_mutex_lock( &p_fifo->lock );
421
422     if( p_fifo->p_first == NULL )
423     {
424         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
425     }
426
427     b = p_fifo->p_first;
428
429     vlc_mutex_unlock( &p_fifo->lock );
430
431     return( b );
432
433 }
434
435 block_t *      block_FifoGetFrame( block_fifo_t *p_fifo )
436 {
437     block_t *b = NULL;
438
439     for( ;; )
440     {
441         block_t *p_next;
442         block_ChainAppend( &b, block_FifoGet( p_fifo ) );
443         p_next = block_FifoShow( p_fifo );
444         if( p_next == NULL || p_next->b_frame_start )
445         {
446             break;
447         }
448     }
449
450     return b;
451 }
452
453