From: Laurent Aimar Date: Mon, 5 Jul 2004 19:50:06 +0000 (+0000) Subject: * block.*: faster block_* and removed unused features. X-Git-Tag: 0.8.0~986 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=1c18e0671289bf9388948b669933785936df8ada;p=vlc * block.*: faster block_* and removed unused features. --- diff --git a/include/vlc_block.h b/include/vlc_block.h index 422433ae8a..399fa50457 100644 --- a/include/vlc_block.h +++ b/include/vlc_block.h @@ -24,9 +24,26 @@ #ifndef _VLC_BLOCK_H #define _VLC_BLOCK_H 1 -/* - * block - */ +/**************************************************************************** + * block: + **************************************************************************** + * - block_sys_t is opaque and thus block_t->p_sys is PRIVATE + * - i_flags may not always be set (ie could be 0, even for a key frame + * it depends where you receive the buffer (before/after a packetizer + * and the demux/packetizer implementations. + * - i_dts/i_pts could be 0, it means no pts + * - i_length: length in microseond of the packet, can be null except in the + * sout where it is mandatory. + * - i_rate 0 or a valid input rate, look at vlc_input.h + * + * - i_buffer number of valid data pointed by p_buffer + * you can freely decrease it but never increase it yourself + * (use block_Realloc) + * - p_buffer: pointer over datas. You should never overwrite it, you can + * only incremment it to skip datas, in others cases use block_Realloc + * (don't duplicate yourself in a bigger buffer, block_Realloc is + * optimised for prehader/postdatas increase) + ****************************************************************************/ typedef struct block_sys_t block_sys_t; /** The content doesn't follow the last block, or is probably broken */ @@ -62,63 +79,172 @@ struct block_t int i_buffer; uint8_t *p_buffer; + /* This way the block_Release can be overloaded + * Don't mess with it now, if you need it the ask on ML + */ void (*pf_release) ( block_t * ); - block_t *(*pf_modify) ( block_t *, vlc_bool_t ); - block_t *(*pf_duplicate) ( block_t * ); - block_t *(*pf_realloc) ( block_t *, int i_prebody, int i_body ); - - /* Following fields are private, user should never touch it */ - /* XXX never touch that OK !!! the first that access that will - * have cvs account removed ;) XXX */ - /* It's an object that should be valid as long as the block_t is valid */ /* It should become a true block manager to reduce malloc/free */ vlc_object_t *p_manager; - /* private member for block_New, .... manager */ + /* Following fields are private, user should never touch it */ + /* XXX never touch that OK !!! the first that access that will + * have cvs account removed ;) XXX */ block_sys_t *p_sys; }; -struct block_fifo_t +/**************************************************************************** + * Blocks functions: + **************************************************************************** + * - block_New : create a new block with the requested size ( >= 0 ), return + * NULL for failure. + * - block_Release : release a block allocated with block_New. + * - block_Realloc : realloc a block, + * i_pre: how many bytes to insert before body if > 0, else how many + * bytes of body to skip (the latter can be done without using + * block_Realloc i_buffer -= -i_pre, p_buffer += -i_pre as i_pre < 0) + * i_body (>= 0): the final size of the body (decreasing it can directly + * be done with i_buffer = i_body). + * with preheader and or body (increase + * and decrease are supported). Use it as it is optimised. + * - block_Duplicate : create a copy of a block. + ****************************************************************************/ +#define block_New( a, b ) __block_New( VLC_OBJECT(a), b ) +VLC_EXPORT( block_t *, __block_New, ( vlc_object_t *, int ) ); +VLC_EXPORT( block_t *, block_Realloc, ( block_t *, int i_pre, int i_body ) ); + +static inline block_t *block_Duplicate( block_t *p_block ) { - vlc_mutex_t lock; /* fifo data lock */ - vlc_cond_t wait; /* fifo data conditional variable */ + block_t *p_dup = block_New( p_block->p_manager, p_block->i_buffer ); - int i_depth; - block_t *p_first; - block_t **pp_last; -}; + if( p_dup && p_block->i_buffer > 0 ) + memcpy( p_dup->p_buffer, p_block->p_buffer, p_block->i_buffer ); -/* - * block - */ -#define block_New( a, b ) __block_New( VLC_OBJECT(a), b ) -VLC_EXPORT( block_t *, __block_New, ( vlc_object_t *, int ) ); + return p_dup; +} static inline void block_Release( block_t *p_block ) { p_block->pf_release( p_block ); } -static inline block_t *block_Modify( block_t *p_block, vlc_bool_t b_willmodify ) + +/**************************************************************************** + * Chains of blocks functions helper + **************************************************************************** + * - block_ChainAppend : append a block the the last block of a chain. Try to + * avoid using with a lot of data as it's really slow, prefer + * block_ChainLastAppend + * - block_ChainLastAppend : use a pointer over a pointer to the next blocks, + * and update it. + * - block_ChainRelease : release a chain of block + * - block_ChainExtract : extract data from a chain, return real bytes counts + * - block_ChainGather : gather a chain, free it and return a block. + ****************************************************************************/ +static inline void block_ChainAppend( block_t **pp_list, block_t *p_block ) { - return p_block->pf_modify( p_block, b_willmodify ); + 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; + } } -static inline block_t *block_Duplicate( block_t *p_block ) + +static inline void block_ChainLastAppend( block_t ***ppp_last, block_t *p_block ) { - return p_block->pf_duplicate( p_block ); + block_t *p_last = p_block; + + **ppp_last = p_block; + + while( p_last->p_next ) p_last = p_last->p_next; + *ppp_last = &p_last->p_next; } -static inline block_t *block_Realloc( block_t *p_block, int i_pre, int i_body ) + +static inline void block_ChainRelease( block_t *p_block ) { - return p_block->pf_realloc( p_block, i_pre, i_body ); + while( p_block ) + { + block_t *p_next = p_block->p_next; + block_Release( p_block ); + p_block = p_next; + } +} +static int block_ChainExtract( block_t *p_list, void *p_data, int i_max ) +{ + block_t *b; + int i_total = 0; + uint8_t *p = (uint8_t*)p_data; + + for( b = p_list; b != NULL; b = b->p_next ) + { + int 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; } -VLC_EXPORT( void, block_ChainAppend, ( block_t **, block_t * ) ); -VLC_EXPORT( void, block_ChainLastAppend, ( block_t ***ppp_last, block_t * ) ); -VLC_EXPORT( void, block_ChainRelease, ( block_t * ) ); -VLC_EXPORT( int, block_ChainExtract, ( block_t *, void *, int ) ); -VLC_EXPORT( block_t *, block_ChainGather, ( block_t * ) ); - -/* a bit special, only for new/other block manager */ -VLC_EXPORT( block_t *, block_NewEmpty, ( void ) ); + +static inline block_t *block_ChainGather( block_t *p_list ) +{ + int i_total = 0; + block_t *b, *g; + + if( p_list->p_next == NULL ) + return p_list; /* Already gathered */ + + 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; +} + + +/**************************************************************************** + * Fifos of blocks. + **************************************************************************** + * Avoid touching block_fifo_t unless you really know what you are doing. + * ( Some race conditions has to be correctly handled, like in win32 ;) + * - block_FifoNew : create and init a new fifo + * - block_FifoRelease : destroy a fifo and free all blocks in it. + * - block_FifoEmpty : free all blocks in a fifo + * - block_FifoPut : put a block + * - block_FifoGet : get a packet from the fifo (and wait if it is empty) + * - block_FifoShow : show the first packet of the fifo (and wait if + * needed), becarefull, you can use it ONLY if you are sure to be the + * only one getting data from the fifo. + ****************************************************************************/ +struct block_fifo_t +{ + vlc_mutex_t lock; /* fifo data lock */ + vlc_cond_t wait; /* fifo data conditional variable */ + + int i_depth; + block_t *p_first; + block_t **pp_last; +}; + #define block_FifoNew( a ) __block_FifoNew( VLC_OBJECT(a) ) VLC_EXPORT( block_fifo_t *, __block_FifoNew, ( vlc_object_t * ) ); diff --git a/src/misc/block.c b/src/misc/block.c index 9d07f63fa4..0404793f78 100644 --- a/src/misc/block.c +++ b/src/misc/block.c @@ -25,117 +25,76 @@ * 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 ); -} - -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; - p_dup->i_length = p_block->i_length; - p_dup->i_rate = p_block->i_rate; +#define BLOCK_PADDING_SIZE 32 +static void BlockRelease( block_t * ); - 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 + */ + 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 ); + block_sys_t *p_sys; - 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; - } - - /* 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 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 ); - BlockRelease( p_block ); + /* Fill all fields */ + 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_rate = 0; + 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_block->pf_release = BlockRelease; + p_block->p_manager = VLC_OBJECT( p_obj->p_vlc ); /* Is ok, as no comunication between p_vlc */ + 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; -} - -static block_t *BlockRealloc( block_t *p_block, int i_prebody, int i_body ) -{ - int i_buffer_size = i_prebody + i_body; + i_buffer_size = i_prebody + i_body; if( i_body < 0 || i_buffer_size <= 0 ) return NULL; - vlc_mutex_lock( &p_block->p_sys->lock ); - if( i_prebody < ( p_block->p_buffer - p_block->p_sys->p_allocated_buffer + p_block->p_sys->i_allocated_buffer ) || p_block->p_buffer - i_prebody > p_block->p_sys->p_allocated_buffer ) @@ -164,174 +123,19 @@ static block_t *BlockRealloc( block_t *p_block, int i_prebody, int i_body ) memcpy( p_rea->p_buffer + i_prebody, p_block->p_buffer, __MIN( p_block->i_buffer, p_rea->i_buffer - i_prebody ) ); - vlc_mutex_unlock( &p_block->p_sys->lock ); block_Release( p_block ); return p_rea; } - vlc_mutex_unlock( &p_block->p_sys->lock ); - - 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_rate = 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_ChainLastAppend( block_t ***ppp_last, block_t *p_block ) -{ - block_t *p_last = p_block; - - /* Append the block */ - **ppp_last = p_block; - - /* Update last pointer */ - while( p_last->p_next ) p_last = p_last->p_next; - *ppp_last = &p_last->p_next; -} - -void block_ChainRelease( 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; - } -} - -int block_ChainExtract( block_t *p_list, void *p_data, int i_max ) +static void BlockRelease( block_t *p_block ) { - 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; + free( p_block ); } -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