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