1 /*****************************************************************************
2 * block.c: Data blocks management functions
3 *****************************************************************************
4 * Copyright (C) 2003-2004 VideoLAN
7 * Authors: Laurent Aimar <fenrir@videolan.org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
31 #include "vlc_block.h"
38 uint8_t *p_allocated_buffer;
39 int i_allocated_buffer;
41 vlc_bool_t b_modify; /* has it been put in modified state */
42 int i_duplicated; /* how many times has the content been
47 static void BlockRelease( block_t *p_block )
49 vlc_mutex_lock( &p_block->p_sys->lock );
51 p_block->p_sys->i_duplicated--;
52 if( p_block->p_sys->i_duplicated < 0 )
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 );
63 vlc_mutex_unlock( &p_block->p_sys->lock );
67 static block_t *__BlockDupContent( block_t *p_block )
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 p_dup->i_length = p_block->i_length;
77 p_dup->i_rate = p_block->i_rate;
82 static block_t *BlockModify( block_t *p_block, vlc_bool_t b_will_modify )
84 block_t *p_mod = p_block; /* by default */
86 vlc_mutex_lock( &p_block->p_sys->lock );
88 if( p_block->p_sys->b_modify == b_will_modify )
90 vlc_mutex_unlock( &p_block->p_sys->lock );
94 if( p_block->p_sys->i_duplicated == 0 )
96 p_block->p_sys->b_modify = b_will_modify;
97 vlc_mutex_unlock( &p_block->p_sys->lock );
101 /* FIXME we could avoid that
102 * we just need to create a new p_sys with new mem FIXME */
103 p_mod = __BlockDupContent( p_block );
104 vlc_mutex_unlock( &p_block->p_sys->lock );
106 BlockRelease( p_block );
111 static block_t *BlockDuplicate( block_t *p_block )
115 vlc_mutex_lock( &p_block->p_sys->lock );
116 if( !p_block->p_sys->b_modify )
118 p_block->p_sys->i_duplicated++;
119 vlc_mutex_unlock( &p_block->p_sys->lock );
120 p_dup = block_NewEmpty();
121 memcpy( p_dup, p_block, sizeof( block_t ) );
122 p_dup->p_next = NULL;
125 p_dup = __BlockDupContent( p_block );
126 vlc_mutex_unlock( &p_block->p_sys->lock );
131 static block_t *BlockRealloc( block_t *p_block, int i_prebody, int i_body )
133 int i_buffer_size = i_prebody + i_body;
135 if( i_body < 0 || i_buffer_size <= 0 ) return NULL;
137 vlc_mutex_lock( &p_block->p_sys->lock );
139 if( i_prebody < ( p_block->p_buffer - p_block->p_sys->p_allocated_buffer +
140 p_block->p_sys->i_allocated_buffer ) ||
141 p_block->p_buffer - i_prebody > p_block->p_sys->p_allocated_buffer )
143 p_block->p_buffer -= i_prebody;
144 p_block->i_buffer += i_prebody;
147 if( p_block->p_buffer + i_body < p_block->p_sys->p_allocated_buffer +
148 p_block->p_sys->i_allocated_buffer )
150 p_block->i_buffer = i_buffer_size;
154 if( i_body > 0 || i_prebody > 0 )
156 block_t *p_rea = block_New( p_block->p_manager, i_buffer_size );
158 p_rea->i_dts = p_block->i_dts;
159 p_rea->i_pts = p_block->i_pts;
160 p_rea->i_flags = p_block->i_flags;
161 p_rea->i_length= p_block->i_length;
162 p_rea->i_rate = p_block->i_rate;
164 memcpy( p_rea->p_buffer + i_prebody, p_block->p_buffer,
165 __MIN( p_block->i_buffer, p_rea->i_buffer - i_prebody ) );
167 vlc_mutex_unlock( &p_block->p_sys->lock );
168 block_Release( p_block );
173 vlc_mutex_unlock( &p_block->p_sys->lock );
178 /*****************************************************************************
179 * Standard block management
181 *****************************************************************************/
182 /* to be used by other block management */
183 block_t *block_NewEmpty( void )
187 p_block = malloc( sizeof( block_t ) );
188 memset( p_block, 0, sizeof( block_t ) );
190 p_block->p_next = NULL;
191 p_block->i_flags = 0;
194 p_block->i_length = 0;
197 p_block->i_buffer = 0;
198 p_block->p_buffer = NULL;
200 p_block->pf_release = NULL;
201 p_block->pf_duplicate = NULL;
202 p_block->pf_modify = NULL;
203 p_block->pf_realloc = NULL;
205 p_block->p_manager = NULL;
206 p_block->p_sys = NULL;
210 block_t *__block_New( vlc_object_t *p_obj, int i_size )
215 p_block = block_NewEmpty();
217 p_block->pf_release = BlockRelease;
218 p_block->pf_duplicate = BlockDuplicate;
219 p_block->pf_modify = BlockModify;
220 p_block->pf_realloc = BlockRealloc;
222 /* that should be ok (no comunication between multiple p_vlc) */
223 p_block->p_manager = VLC_OBJECT( p_obj->p_vlc );
225 p_block->p_sys = p_sys = malloc( sizeof( block_sys_t ) );
226 vlc_mutex_init( p_obj, &p_sys->lock );
228 /* XXX align on 16 and add 32 prebuffer/posbuffer bytes */
229 p_sys->i_allocated_buffer = i_size + 32 + 32 + 16;
230 p_sys->p_allocated_buffer = malloc( p_sys->i_allocated_buffer );
231 p_block->i_buffer = i_size;
232 p_block->p_buffer = &p_sys->p_allocated_buffer[32+15-((long)p_sys->p_allocated_buffer % 16 )];
234 p_sys->i_duplicated = 0;
235 p_sys->b_modify = VLC_TRUE;
240 void block_ChainAppend( block_t **pp_list, block_t *p_block )
242 if( *pp_list == NULL )
248 block_t *p = *pp_list;
258 void block_ChainLastAppend( block_t ***ppp_last, block_t *p_block )
260 block_t *p_last = p_block;
262 /* Append the block */
263 **ppp_last = p_block;
265 /* Update last pointer */
266 while( p_last->p_next ) p_last = p_last->p_next;
267 *ppp_last = &p_last->p_next;
270 void block_ChainRelease( block_t *p_block )
275 p_next = p_block->p_next;
276 p_block->pf_release( p_block );
281 int block_ChainExtract( block_t *p_list, void *p_data, int i_max )
287 for( b = p_list; b != NULL; b = b->p_next )
291 i_copy = __MIN( i_max, b->i_buffer );
294 memcpy( p, b->p_buffer, i_copy );
308 block_t *block_ChainGather( block_t *p_list )
313 if( p_list->p_next == NULL )
315 /* only one, so no need */
319 for( b = p_list; b != NULL; b = b->p_next )
321 i_total += b->i_buffer;
324 g = block_New( p_list->p_manager, i_total );
325 block_ChainExtract( p_list, g->p_buffer, g->i_buffer );
327 g->i_flags = p_list->i_flags;
328 g->i_pts = p_list->i_pts;
329 g->i_dts = p_list->i_dts;
332 block_ChainRelease( p_list );
336 /*****************************************************************************
337 * block_fifo_t management
338 *****************************************************************************/
339 block_fifo_t *__block_FifoNew( vlc_object_t *p_obj )
341 block_fifo_t *p_fifo;
343 p_fifo = malloc( sizeof( vlc_object_t ) );
344 vlc_mutex_init( p_obj, &p_fifo->lock );
345 vlc_cond_init( p_obj, &p_fifo->wait );
347 p_fifo->p_first = NULL;
348 p_fifo->pp_last = &p_fifo->p_first;
353 void block_FifoRelease( block_fifo_t *p_fifo )
355 block_FifoEmpty( p_fifo );
356 vlc_cond_destroy( &p_fifo->wait );
357 vlc_mutex_destroy( &p_fifo->lock );
361 void block_FifoEmpty( block_fifo_t *p_fifo )
365 vlc_mutex_lock( &p_fifo->lock );
366 for( b = p_fifo->p_first; b != NULL; )
376 p_fifo->p_first = NULL;
377 p_fifo->pp_last = &p_fifo->p_first;
378 vlc_mutex_unlock( &p_fifo->lock );
381 int block_FifoPut( block_fifo_t *p_fifo, block_t *p_block )
384 vlc_mutex_lock( &p_fifo->lock );
388 i_size += p_block->i_buffer;
390 *p_fifo->pp_last = p_block;
391 p_fifo->pp_last = &p_block->p_next;
394 p_block = p_block->p_next;
398 /* warn there is data in this fifo */
399 vlc_cond_signal( &p_fifo->wait );
400 vlc_mutex_unlock( &p_fifo->lock );
405 block_t *block_FifoGet( block_fifo_t *p_fifo )
409 vlc_mutex_lock( &p_fifo->lock );
411 /* We do a while here because there is a race condition in the
412 * win32 implementation of vlc_cond_wait() (We can't be sure the fifo
413 * hasn't been emptied again since we were signaled). */
414 while( p_fifo->p_first == NULL )
416 vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
421 p_fifo->p_first = b->p_next;
424 if( p_fifo->p_first == NULL )
426 p_fifo->pp_last = &p_fifo->p_first;
429 vlc_mutex_unlock( &p_fifo->lock );
435 block_t *block_FifoShow( block_fifo_t *p_fifo )
439 vlc_mutex_lock( &p_fifo->lock );
441 if( p_fifo->p_first == NULL )
443 vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
448 vlc_mutex_unlock( &p_fifo->lock );