X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fblock.c;h=694acf8d0f01d97f6e41ddb8336b39ec15e187d5;hb=bd3484b93bb6ebf0ece8a8db8acf29f52d007660;hp=5a093f5bb7bfdc3d23268effd93cc61263eb6ad1;hpb=a3a165edc5ef56dc862c932ff1b78ec98c6ed16d;p=vlc diff --git a/src/misc/block.c b/src/misc/block.c index 5a093f5bb7..694acf8d0f 100644 --- a/src/misc/block.c +++ b/src/misc/block.c @@ -1,7 +1,7 @@ /***************************************************************************** * block.c: Data blocks management functions ***************************************************************************** - * Copyright (C) 2003-2004 VideoLAN + * Copyright (C) 2003-2004 the VideoLAN team * $Id$ * * Authors: Laurent Aimar @@ -18,158 +18,119 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ #include -#include #include #include "vlc_block.h" +/***************************************************************************** + * Block functions. + *****************************************************************************/ /* private */ struct block_sys_t { - vlc_mutex_t lock; - uint8_t *p_allocated_buffer; int i_allocated_buffer; - - vlc_bool_t b_modify; /* has it been put in modified state */ - int i_duplicated; /* how many times has the content been - * duplicated */ - }; -static void BlockRelease( block_t *p_block ) -{ - vlc_mutex_lock( &p_block->p_sys->lock ); - - p_block->p_sys->i_duplicated--; - if( p_block->p_sys->i_duplicated < 0 ) - { - vlc_mutex_unlock( &p_block->p_sys->lock ); - vlc_mutex_destroy( &p_block->p_sys->lock ); - free( p_block->p_sys->p_allocated_buffer ); - free( p_block->p_sys ); - free( p_block ); - - return; - } - - vlc_mutex_unlock( &p_block->p_sys->lock ); - free( p_block ); -} +#define BLOCK_PADDING_SIZE 32 +static void BlockRelease( block_t * ); -static block_t *__BlockDupContent( block_t *p_block ) -{ - block_t *p_dup; - - p_dup = block_New( p_block->p_manager, p_block->i_buffer ); - memcpy( p_dup->p_buffer, p_block->p_buffer, p_block->i_buffer ); - p_dup->i_flags = p_block->i_flags; - p_dup->i_pts = p_block->i_pts; - p_dup->i_dts = p_block->i_dts; - - return p_dup; -} - -static block_t *BlockModify( block_t *p_block, vlc_bool_t b_will_modify ) +block_t *__block_New( vlc_object_t *p_obj, int i_size ) { - block_t *p_mod = p_block; /* by default */ - - vlc_mutex_lock( &p_block->p_sys->lock ); + /* We do only one malloc + * TODO bench if doing 2 malloc but keeping a pool of buffer is better + * 16 -> align on 16 + * 2 * BLOCK_PADDING_SIZE -> pre + post padding + */ + block_sys_t *p_sys; + const int i_alloc = i_size + 2 * BLOCK_PADDING_SIZE + 16; + block_t *p_block = + malloc( sizeof( block_t ) + sizeof( block_sys_t ) + i_alloc ); - if( p_block->p_sys->b_modify == b_will_modify ) - { - vlc_mutex_unlock( &p_block->p_sys->lock ); - return p_block; - } + if( p_block == NULL ) return NULL; - if( p_block->p_sys->i_duplicated == 0 ) - { - p_block->p_sys->b_modify = b_will_modify; - vlc_mutex_unlock( &p_block->p_sys->lock ); - return p_block; - } + /* Fill opaque data */ + p_sys = (block_sys_t*)( (uint8_t*)p_block + sizeof( block_t ) ); + p_sys->i_allocated_buffer = i_alloc; + p_sys->p_allocated_buffer = (uint8_t*)p_block + sizeof( block_t ) + + sizeof( block_sys_t ); - /* FIXME we could avoid that - * we just need to create a new p_sys with new mem FIXME */ - p_mod = __BlockDupContent( p_block ); - vlc_mutex_unlock( &p_block->p_sys->lock ); + /* Fill all fields */ + p_block->p_next = NULL; + p_block->p_prev = NULL; + p_block->i_flags = 0; + p_block->i_pts = 0; + p_block->i_dts = 0; + p_block->i_length = 0; + p_block->i_rate = 0; + p_block->i_buffer = i_size; + p_block->p_buffer = + &p_sys->p_allocated_buffer[BLOCK_PADDING_SIZE + + 16 - ((uintptr_t)p_sys->p_allocated_buffer % 16 )]; + p_block->pf_release = BlockRelease; - BlockRelease( p_block ); + /* Is ok, as no comunication between p_vlc */ + p_block->p_manager = VLC_OBJECT( p_obj->p_libvlc ); + p_block->p_sys = p_sys; - return p_mod; + return p_block; } -static block_t *BlockDuplicate( block_t *p_block ) +block_t *block_Realloc( block_t *p_block, int i_prebody, int i_body ) { - block_t *p_dup; + int i_buffer_size; - vlc_mutex_lock( &p_block->p_sys->lock ); - if( !p_block->p_sys->b_modify ) + if( p_block->pf_release != BlockRelease ) { - p_block->p_sys->i_duplicated++; - vlc_mutex_unlock( &p_block->p_sys->lock ); - p_dup = block_NewEmpty(); - memcpy( p_dup, p_block, sizeof( block_t ) ); - p_dup->p_next = NULL; - return p_dup; + /* Special case when pf_release if overloaded + * TODO if used one day, them implement it in a smarter way */ + block_t *p_dup = block_Duplicate( p_block ); + block_Release( p_block ); + + p_block = p_dup; } - p_dup = __BlockDupContent( p_block ); - vlc_mutex_unlock( &p_block->p_sys->lock ); - return p_dup; -} + i_buffer_size = i_prebody + i_body; -static block_t *BlockRealloc( block_t *p_block, int i_prebody, int i_body ) -{ + if( i_body < 0 || i_buffer_size <= 0 ) return NULL; - vlc_mutex_lock( &p_block->p_sys->lock ); - if( i_prebody < 0 || p_block->p_buffer - i_prebody > - p_block->p_sys->p_allocated_buffer ) + if( p_block->p_buffer - i_prebody > p_block->p_sys->p_allocated_buffer && + p_block->p_buffer - i_prebody < p_block->p_sys->p_allocated_buffer + + p_block->p_sys->i_allocated_buffer ) { p_block->p_buffer -= i_prebody; p_block->i_buffer += i_prebody; i_prebody = 0; } - if( i_body < 0 || - p_block->p_buffer + i_body < p_block->p_sys->p_allocated_buffer + + if( p_block->p_buffer + i_body < p_block->p_sys->p_allocated_buffer + p_block->p_sys->i_allocated_buffer ) { - p_block->i_buffer = i_body; + p_block->i_buffer = i_buffer_size; i_body = 0; } - vlc_mutex_unlock( &p_block->p_sys->lock ); - if( i_prebody > 0 ) + if( i_body > 0 || i_prebody > 0 ) { - block_t *p_rea = block_New( p_block->p_manager, i_prebody + i_body ); + block_t *p_rea = block_New( p_block->p_manager, i_buffer_size ); - memcpy( &p_rea->p_buffer[i_prebody], p_block->p_buffer, - p_block->i_buffer ); + p_rea->i_dts = p_block->i_dts; + p_rea->i_pts = p_block->i_pts; + p_rea->i_flags = p_block->i_flags; + p_rea->i_length = p_block->i_length; + p_rea->i_rate = p_block->i_rate; + p_rea->i_samples = p_block->i_samples; - return p_rea; - } - - if( i_body > 0 ) - { - int i_start; - block_t *p_rea = BlockModify( p_block, VLC_TRUE ); + memcpy( p_rea->p_buffer + i_prebody, p_block->p_buffer, + __MIN( p_block->i_buffer, p_rea->i_buffer - i_prebody ) ); - i_start = p_rea->p_buffer - p_rea->p_sys->p_allocated_buffer; - - p_rea->p_sys->i_allocated_buffer += i_body - p_rea->i_buffer; - p_rea->p_sys->p_allocated_buffer = - realloc( p_rea->p_sys->p_allocated_buffer, - p_rea->p_sys->i_allocated_buffer ); - - p_rea->p_buffer = &p_rea->p_sys->p_allocated_buffer[i_start]; - p_rea->i_buffer = i_body; + block_Release( p_block ); return p_rea; } @@ -177,151 +138,11 @@ static block_t *BlockRealloc( block_t *p_block, int i_prebody, int i_body ) return p_block; } -/***************************************************************************** - * Standard block management - * - *****************************************************************************/ -/* to be used by other block management */ -block_t *block_NewEmpty( void ) -{ - block_t *p_block; - - p_block = malloc( sizeof( block_t ) ); - memset( p_block, 0, sizeof( block_t ) ); - - p_block->p_next = NULL; - p_block->i_flags = 0; - p_block->i_pts = 0; - p_block->i_dts = 0; - p_block->i_length = 0; - - p_block->i_buffer = 0; - p_block->p_buffer = NULL; - - p_block->pf_release = NULL; - p_block->pf_duplicate = NULL; - p_block->pf_modify = NULL; - p_block->pf_realloc = NULL; - - p_block->p_manager = NULL; - p_block->p_sys = NULL; - return p_block; -} - -block_t *__block_New( vlc_object_t *p_obj, int i_size ) -{ - block_t *p_block; - block_sys_t *p_sys; - - p_block = block_NewEmpty(); - - p_block->pf_release = BlockRelease; - p_block->pf_duplicate = BlockDuplicate; - p_block->pf_modify = BlockModify; - p_block->pf_realloc = BlockRealloc; - - /* that should be ok (no comunication between multiple p_vlc) */ - p_block->p_manager = VLC_OBJECT( p_obj->p_vlc ); - - p_block->p_sys = p_sys = malloc( sizeof( block_sys_t ) ); - vlc_mutex_init( p_obj, &p_sys->lock ); - - /* XXX align on 16 and add 32 prebuffer/posbuffer bytes */ - p_sys->i_allocated_buffer = i_size + 32 + 32 + 16; - p_sys->p_allocated_buffer = malloc( p_sys->i_allocated_buffer ); - p_block->i_buffer = i_size; - p_block->p_buffer = &p_sys->p_allocated_buffer[32+15-((long)p_sys->p_allocated_buffer % 16 )]; - - p_sys->i_duplicated = 0; - p_sys->b_modify = VLC_TRUE; - - return p_block; -} - -void block_ChainAppend( block_t **pp_list, block_t *p_block ) -{ - - if( *pp_list == NULL ) - { - *pp_list = p_block; - } - else - { - block_t *p = *pp_list; - - while( p->p_next ) - { - p = p->p_next; - } - p->p_next = p_block; - } -} - -void block_ChainRelease( block_t *p_block ) +static void BlockRelease( block_t *p_block ) { - while( p_block ) - { - block_t *p_next; - p_next = p_block->p_next; - p_block->pf_release( p_block ); - p_block = p_next; - } + free( p_block ); } -int block_ChainExtract( block_t *p_list, void *p_data, int i_max ) -{ - block_t *b; - int i_total = 0; - uint8_t *p = p_data; - - for( b = p_list; b != NULL; b = b->p_next ) - { - int i_copy; - - i_copy = __MIN( i_max, b->i_buffer ); - if( i_copy > 0 ) - { - memcpy( p, b->p_buffer, i_copy ); - i_max -= i_copy; - i_total += i_copy; - p += i_copy; - - if( i_max == 0 ) - { - return i_total; - } - } - } - return i_total; -} - -block_t *block_ChainGather( block_t *p_list ) -{ - int i_total = 0; - block_t *b, *g; - - if( p_list->p_next == NULL ) - { - /* only one, so no need */ - return p_list; - } - - for( b = p_list; b != NULL; b = b->p_next ) - { - i_total += b->i_buffer; - } - - g = block_New( p_list->p_manager, i_total ); - block_ChainExtract( p_list, g->p_buffer, g->i_buffer ); - - g->i_flags = p_list->i_flags; - g->i_pts = p_list->i_pts; - g->i_dts = p_list->i_dts; - - /* free p_list */ - block_ChainRelease( p_list ); - return g; -} /***************************************************************************** * block_fifo_t management @@ -330,10 +151,10 @@ block_fifo_t *__block_FifoNew( vlc_object_t *p_obj ) { block_fifo_t *p_fifo; - p_fifo = malloc( sizeof( vlc_object_t ) ); + p_fifo = malloc( sizeof( block_fifo_t ) ); vlc_mutex_init( p_obj, &p_fifo->lock ); vlc_cond_init( p_obj, &p_fifo->wait ); - p_fifo->i_depth = 0; + p_fifo->i_depth = p_fifo->i_size = 0; p_fifo->p_first = NULL; p_fifo->pp_last = &p_fifo->p_first; @@ -362,7 +183,7 @@ void block_FifoEmpty( block_fifo_t *p_fifo ) b = p_next; } - p_fifo->i_depth = 0; + p_fifo->i_depth = p_fifo->i_size = 0; p_fifo->p_first = NULL; p_fifo->pp_last = &p_fifo->p_first; vlc_mutex_unlock( &p_fifo->lock ); @@ -380,6 +201,7 @@ int block_FifoPut( block_fifo_t *p_fifo, block_t *p_block ) *p_fifo->pp_last = p_block; p_fifo->pp_last = &p_block->p_next; p_fifo->i_depth++; + p_fifo->i_size += p_block->i_buffer; p_block = p_block->p_next; @@ -398,7 +220,10 @@ block_t *block_FifoGet( block_fifo_t *p_fifo ) vlc_mutex_lock( &p_fifo->lock ); - if( p_fifo->p_first == NULL ) + /* We do a while here because there is a race condition in the + * win32 implementation of vlc_cond_wait() (We can't be sure the fifo + * hasn't been emptied again since we were signaled). */ + while( p_fifo->p_first == NULL ) { vlc_cond_wait( &p_fifo->wait, &p_fifo->lock ); } @@ -407,6 +232,7 @@ block_t *block_FifoGet( block_fifo_t *p_fifo ) p_fifo->p_first = b->p_next; p_fifo->i_depth--; + p_fifo->i_size -= b->i_buffer; if( p_fifo->p_first == NULL ) { @@ -416,7 +242,7 @@ block_t *block_FifoGet( block_fifo_t *p_fifo ) vlc_mutex_unlock( &p_fifo->lock ); b->p_next = NULL; - return( b ); + return b; } block_t *block_FifoShow( block_fifo_t *p_fifo )