X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Ffilter_chain.c;h=3fd4c31991ce7e43b6a75788a436a850109cb6a9;hb=6197b056e6f9bd026012db6f1512bbd981e27442;hp=255a25e101a661aaebc64ef219f1d2caddccf488;hpb=0b5502c3d8bf855bc8ea4352d079a6cfe5844b59;p=vlc diff --git a/src/misc/filter_chain.c b/src/misc/filter_chain.c index 255a25e101..3fd4c31991 100644 --- a/src/misc/filter_chain.c +++ b/src/misc/filter_chain.c @@ -26,9 +26,9 @@ #endif #include -#include #include #include +#include typedef struct { @@ -38,10 +38,27 @@ typedef struct } filter_chain_allocator_t; -static int AllocatorInit( const filter_chain_allocator_t *, filter_t * ); -static void AllocatorClean( const filter_chain_allocator_t *, filter_t * ); +typedef struct chained_filter_t +{ + /* Public part of the filter structure */ + filter_t filter; + /* Private filter chain data (shhhh!) */ + struct chained_filter_t *prev, *next; + vlc_mouse_t *mouse; +} chained_filter_t; + +/* Only use this with filter objects from _this_ C module */ +static inline chained_filter_t *chained (filter_t *filter) +{ + return (chained_filter_t *)filter; +} -static bool IsInternalVideoAllocator( filter_t * ); +static int AllocatorInit( const filter_chain_allocator_t *, + chained_filter_t * ); +static void AllocatorClean( const filter_chain_allocator_t *, + chained_filter_t * ); + +static bool IsInternalVideoAllocator( chained_filter_t * ); static int InternalVideoInit( filter_t *, void * ); static void InternalVideoClean( filter_t * ); @@ -55,27 +72,16 @@ static const filter_chain_allocator_t internal_video_allocator = { /* */ struct filter_chain_t { - /* Parent object */ - vlc_object_t *p_this; - - /* List of filters */ - vlc_array_t filters; - vlc_array_t mouses; - - /* Capability of all the filters in the chain */ - char *psz_capability; + vlc_object_t *p_this; /**< Owner object */ + filter_chain_allocator_t allocator; /**< Owner allocation callbacks */ - /* Input format (read only) */ - es_format_t fmt_in; + chained_filter_t *first, *last; /**< List of filters */ - /* allow changing fmt_out if true */ - bool b_allow_fmt_out_change; - - /* Output format (writable depending on ... */ - es_format_t fmt_out; - - /* User provided allocator */ - filter_chain_allocator_t allocator; + es_format_t fmt_in; /**< Chain input format (constant) */ + es_format_t fmt_out; /**< Chain current output format */ + unsigned length; /**< Number of filters */ + bool b_allow_fmt_out_change; /**< Can the output format be changed? */ + char psz_capability[1]; /**< Module capability for all chained filters */ }; /** @@ -91,31 +97,30 @@ static int filter_chain_DeleteFilterInternal( filter_chain_t *, filter_t * ); static int UpdateBufferFunctions( filter_chain_t * ); +#undef filter_chain_New /** * Filter chain initialisation */ -filter_chain_t *__filter_chain_New( vlc_object_t *p_this, - const char *psz_capability, - bool b_allow_fmt_out_change, - int (*pf_buffer_allocation_init)( filter_t *, void * ), - void (*pf_buffer_allocation_clean)( filter_t * ), - void *p_buffer_allocation_data ) +filter_chain_t *filter_chain_New( vlc_object_t *p_this, + const char *psz_capability, + bool b_allow_fmt_out_change, + int (*pf_buffer_allocation_init)( filter_t *, void * ), + void (*pf_buffer_allocation_clean)( filter_t * ), + void *p_buffer_allocation_data ) { - filter_chain_t *p_chain = malloc( sizeof( *p_chain ) ); + assert( p_this ); + assert( psz_capability ); + + size_t size = sizeof(filter_chain_t) + strlen(psz_capability); + filter_chain_t *p_chain = malloc( size ); if( !p_chain ) return NULL; p_chain->p_this = p_this; - vlc_array_init( &p_chain->filters ); - vlc_array_init( &p_chain->mouses ); - p_chain->psz_capability = strdup( psz_capability ); - if( !p_chain->psz_capability ) - { - vlc_array_clear( &p_chain->mouses ); - vlc_array_clear( &p_chain->filters ); - free( p_chain ); - return NULL; - } + p_chain->last = p_chain->first = NULL; + p_chain->length = 0; + strcpy( p_chain->psz_capability, psz_capability ); + es_format_Init( &p_chain->fmt_in, UNKNOWN_ES, 0 ); es_format_Init( &p_chain->fmt_out, UNKNOWN_ES, 0 ); p_chain->b_allow_fmt_out_change = b_allow_fmt_out_change; @@ -137,9 +142,6 @@ void filter_chain_Delete( filter_chain_t *p_chain ) es_format_Clean( &p_chain->fmt_in ); es_format_Clean( &p_chain->fmt_out ); - free( p_chain->psz_capability ); - vlc_array_clear( &p_chain->mouses ); - vlc_array_clear( &p_chain->filters ); free( p_chain ); } /** @@ -148,12 +150,11 @@ void filter_chain_Delete( filter_chain_t *p_chain ) void filter_chain_Reset( filter_chain_t *p_chain, const es_format_t *p_fmt_in, const es_format_t *p_fmt_out ) { - while( vlc_array_count( &p_chain->filters ) > 0 ) - { - filter_t *p_filter = vlc_array_item_at_index( &p_chain->filters, 0 ); + filter_t *p_filter; + while( (p_filter = &p_chain->first->filter) != NULL ) filter_chain_DeleteFilterInternal( p_chain, p_filter ); - } + if( p_fmt_in ) { es_format_Clean( &p_chain->fmt_in ); @@ -203,7 +204,7 @@ int filter_chain_DeleteFilter( filter_chain_t *p_chain, filter_t *p_filter ) int filter_chain_GetLength( filter_chain_t *p_chain ) { - return vlc_array_count( &p_chain->filters ); + return p_chain->length; } const es_format_t *filter_chain_GetFmtOut( filter_chain_t *p_chain ) @@ -212,12 +213,8 @@ const es_format_t *filter_chain_GetFmtOut( filter_chain_t *p_chain ) if( p_chain->b_allow_fmt_out_change ) return &p_chain->fmt_out; - const int i_count = vlc_array_count( &p_chain->filters ); - if( i_count > 0 ) - { - filter_t *p_last = vlc_array_item_at_index( &p_chain->filters, i_count - 1 ); - return &p_last->fmt_out; - } + if( p_chain->last != NULL ) + return &p_chain->last->filter.fmt_out; /* Unless filter_chain_Reset has been called we are doomed */ return &p_chain->fmt_out; @@ -225,9 +222,9 @@ const es_format_t *filter_chain_GetFmtOut( filter_chain_t *p_chain ) picture_t *filter_chain_VideoFilter( filter_chain_t *p_chain, picture_t *p_pic ) { - for( int i = 0; i < vlc_array_count( &p_chain->filters ); i++ ) + for( chained_filter_t *f = p_chain->first; f != NULL; f = f->next ) { - filter_t *p_filter = vlc_array_item_at_index( &p_chain->filters, i ); + filter_t *p_filter = &f->filter; p_pic = p_filter->pf_video_filter( p_filter, p_pic ); if( !p_pic ) @@ -238,9 +235,9 @@ picture_t *filter_chain_VideoFilter( filter_chain_t *p_chain, picture_t *p_pic ) block_t *filter_chain_AudioFilter( filter_chain_t *p_chain, block_t *p_block ) { - for( int i = 0; i < vlc_array_count( &p_chain->filters ); i++ ) + for( chained_filter_t *f = p_chain->first; f != NULL; f = f->next ) { - filter_t *p_filter = vlc_array_item_at_index( &p_chain->filters, i ); + filter_t *p_filter = &f->filter; p_block = p_filter->pf_audio_filter( p_filter, p_block ); if( !p_block ) @@ -252,10 +249,9 @@ block_t *filter_chain_AudioFilter( filter_chain_t *p_chain, block_t *p_block ) void filter_chain_SubFilter( filter_chain_t *p_chain, mtime_t display_date ) { - for( int i = 0; i < vlc_array_count( &p_chain->filters ); i++ ) + for( chained_filter_t *f = p_chain->first; f != NULL; f = f->next ) { - filter_t *p_filter = vlc_array_item_at_index( &p_chain->filters, i ); - + filter_t *p_filter = &f->filter; subpicture_t *p_subpic = p_filter->pf_sub_filter( p_filter, display_date ); /* XXX I find that spu_t cast ugly */ if( p_subpic ) @@ -267,18 +263,18 @@ int filter_chain_MouseFilter( filter_chain_t *p_chain, vlc_mouse_t *p_dst, const { vlc_mouse_t current = *p_src; - for( int i = vlc_array_count( &p_chain->filters ) - 1; i >= 0; i-- ) + for( chained_filter_t *f = p_chain->first; f != NULL; f = f->next ) { - filter_t *p_filter = vlc_array_item_at_index( &p_chain->filters, i ); - vlc_mouse_t *p_mouse = vlc_array_item_at_index( &p_chain->mouses, i ); + filter_t *p_filter = &f->filter; + vlc_mouse_t *p_mouse = f->mouse; - if( p_filter->pf_mouse && p_mouse ) + if( p_filter->pf_video_mouse && p_mouse ) { vlc_mouse_t old = *p_mouse; vlc_mouse_t filtered; *p_mouse = current; - if( p_filter->pf_mouse( p_filter, &filtered, &old, ¤t ) ) + if( p_filter->pf_video_mouse( p_filter, &filtered, &old, ¤t ) ) return VLC_EGENERIC; current = filtered; } @@ -288,6 +284,25 @@ int filter_chain_MouseFilter( filter_chain_t *p_chain, vlc_mouse_t *p_dst, const return VLC_SUCCESS; } +int filter_chain_MouseEvent( filter_chain_t *p_chain, + const vlc_mouse_t *p_mouse, + const video_format_t *p_fmt ) +{ + for( chained_filter_t *f = p_chain->first; f != NULL; f = f->next ) + { + filter_t *p_filter = &f->filter; + + if( p_filter->pf_sub_mouse ) + { + vlc_mouse_t old = *f->mouse; + *f->mouse = *p_mouse; + if( p_filter->pf_sub_mouse( p_filter, &old, p_mouse, p_fmt ) ) + return VLC_EGENERIC; + } + } + + return VLC_SUCCESS; +} /* Helpers */ static filter_t *filter_chain_AppendFilterInternal( filter_chain_t *p_chain, @@ -296,22 +311,20 @@ static filter_t *filter_chain_AppendFilterInternal( filter_chain_t *p_chain, const es_format_t *p_fmt_in, const es_format_t *p_fmt_out ) { - filter_t *p_filter = vlc_custom_create( p_chain->p_this, sizeof(*p_filter), - VLC_OBJECT_GENERIC, "filter" ); + chained_filter_t *p_chained = + vlc_custom_create( p_chain->p_this, sizeof(*p_chained), + VLC_OBJECT_GENERIC, "filter" ); + filter_t *p_filter = &p_chained->filter; if( !p_filter ) return NULL; vlc_object_attach( p_filter, p_chain->p_this ); if( !p_fmt_in ) { - p_fmt_in = &p_chain->fmt_in; - - const int i_count = vlc_array_count( &p_chain->filters ); - if( i_count > 0 ) - { - filter_t *p_last = vlc_array_item_at_index( &p_chain->filters, i_count - 1 ); - p_fmt_in = &p_last->fmt_out; - } + if( p_chain->last != NULL ) + p_fmt_in = &p_chain->last->filter.fmt_out; + else + p_fmt_in = &p_chain->fmt_in; } if( !p_fmt_out ) @@ -336,18 +349,29 @@ static filter_t *filter_chain_AppendFilterInternal( filter_chain_t *p_chain, es_format_Copy( &p_chain->fmt_out, &p_filter->fmt_out ); } - if( AllocatorInit( &p_chain->allocator, p_filter ) ) + if( AllocatorInit( &p_chain->allocator, p_chained ) ) goto error; - vlc_array_append( &p_chain->filters, p_filter ); + if( p_chain->last == NULL ) + { + assert( p_chain->first == NULL ); + p_chain->first = p_chained; + } + else + p_chain->last->next = p_chained; + p_chained->prev = p_chain->last; + p_chain->last = p_chained; + p_chained->next = NULL; + p_chain->length++; vlc_mouse_t *p_mouse = malloc( sizeof(*p_mouse) ); if( p_mouse ) vlc_mouse_Init( p_mouse ); - vlc_array_append( &p_chain->mouses, p_mouse ); + p_chained->mouse = p_mouse; msg_Dbg( p_chain->p_this, "Filter '%s' (%p) appended to chain", - psz_name ? psz_name : p_filter->psz_object_name, p_filter ); + psz_name ? psz_name : module_get_name(p_filter->p_module, false), + p_filter ); return p_filter; @@ -362,7 +386,6 @@ error: module_unneed( p_filter, p_filter->p_module ); es_format_Clean( &p_filter->fmt_in ); es_format_Clean( &p_filter->fmt_out ); - vlc_object_detach( p_filter ); vlc_object_release( p_filter ); return NULL; } @@ -406,37 +429,39 @@ static int filter_chain_AppendFromStringInternal( filter_chain_t *p_chain, static int filter_chain_DeleteFilterInternal( filter_chain_t *p_chain, filter_t *p_filter ) { - const int i_filter_idx = vlc_array_index_of_item( &p_chain->filters, p_filter ); - if( i_filter_idx < 0 ) + chained_filter_t *p_chained = chained( p_filter ); + + /* Remove it from the chain */ + if( p_chained->prev != NULL ) + p_chained->prev->next = p_chained->next; + else { - /* Oops, filter wasn't found - * FIXME shoulnd't it be an assert instead ? */ - msg_Err( p_chain->p_this, - "Couldn't find filter '%s' (%p) when trying to remove it from chain", - p_filter->psz_object_name, p_filter ); - return VLC_EGENERIC; + assert( p_chained == p_chain->first ); + p_chain->first = p_chained->next; } - /* Remove it from the chain */ - vlc_array_remove( &p_chain->filters, i_filter_idx ); + if( p_chained->next != NULL ) + p_chained->next->prev = p_chained->prev; + else + { + assert( p_chained == p_chain->last ); + p_chain->last = p_chained->prev; + } + p_chain->length--; - msg_Dbg( p_chain->p_this, "Filter '%s' (%p) removed from chain", - p_filter->psz_object_name, p_filter ); + msg_Dbg( p_chain->p_this, "Filter %p removed from chain", p_filter ); /* Destroy the filter object */ - if( IsInternalVideoAllocator( p_filter ) ) - AllocatorClean( &internal_video_allocator, p_filter ); + if( IsInternalVideoAllocator( p_chained ) ) + AllocatorClean( &internal_video_allocator, p_chained ); else - AllocatorClean( &p_chain->allocator, p_filter ); + AllocatorClean( &p_chain->allocator, p_chained ); - vlc_object_detach( p_filter ); if( p_filter->p_module ) module_unneed( p_filter, p_filter->p_module ); + free( p_chained->mouse ); vlc_object_release( p_filter ); - vlc_mouse_t *p_mouse = vlc_array_item_at_index( &p_chain->mouses, i_filter_idx ); - free( p_mouse ); - vlc_array_remove( &p_chain->mouses, i_filter_idx ); /* FIXME: check fmt_in/fmt_out consitency */ return VLC_SUCCESS; @@ -455,31 +480,32 @@ static int UpdateVideoBufferFunctions( filter_chain_t *p_chain ) * filter without having to worry about the parent's picture * heap format. */ - const int i_count = vlc_array_count( &p_chain->filters ); - for( int i = 0; i < i_count - 1; i++ ) - { - filter_t *p_filter = vlc_array_item_at_index( &p_chain->filters, i ); + /* FIXME: we should only update the last and penultimate filters */ + chained_filter_t *f; - if( !IsInternalVideoAllocator( p_filter ) ) + for( f = p_chain->first; f != p_chain->last; f = f->next ) + { + if( !IsInternalVideoAllocator( f ) ) { - AllocatorClean( &p_chain->allocator, p_filter ); + AllocatorClean( &p_chain->allocator, f ); - AllocatorInit( &internal_video_allocator, p_filter ); + AllocatorInit( &internal_video_allocator, f ); } } - if( i_count >= 1 ) + + if( f != NULL ) { - filter_t * p_filter = vlc_array_item_at_index( &p_chain->filters, i_count - 1 ); - if( IsInternalVideoAllocator( p_filter ) ) + if( IsInternalVideoAllocator( f ) ) { - AllocatorClean( &internal_video_allocator, p_filter ); + AllocatorClean( &internal_video_allocator, f ); - if( AllocatorInit( &p_chain->allocator, p_filter ) ) + if( AllocatorInit( &p_chain->allocator, f ) ) return VLC_EGENERIC; } } return VLC_SUCCESS; } + /** * This function should be called after every filter chain change */ @@ -496,9 +522,7 @@ static picture_t *VideoBufferNew( filter_t *p_filter ) { const video_format_t *p_fmt = &p_filter->fmt_out.video; - picture_t *p_picture = picture_New( p_fmt->i_chroma, - p_fmt->i_width, p_fmt->i_height, - p_fmt->i_aspect ); + picture_t *p_picture = picture_NewFromFormat( p_fmt ); if( !p_picture ) msg_Err( p_filter, "Failed to allocate picture" ); return p_picture; @@ -512,31 +536,35 @@ static int InternalVideoInit( filter_t *p_filter, void *p_data ) { VLC_UNUSED(p_data); - p_filter->pf_vout_buffer_new = VideoBufferNew; - p_filter->pf_vout_buffer_del = VideoBufferDelete; + p_filter->pf_video_buffer_new = VideoBufferNew; + p_filter->pf_video_buffer_del = VideoBufferDelete; return VLC_SUCCESS; } static void InternalVideoClean( filter_t *p_filter ) { - p_filter->pf_vout_buffer_new = NULL; - p_filter->pf_vout_buffer_del = NULL; + p_filter->pf_video_buffer_new = NULL; + p_filter->pf_video_buffer_del = NULL; } -static bool IsInternalVideoAllocator( filter_t *p_filter ) + +static bool IsInternalVideoAllocator( chained_filter_t *p_filter ) { - return p_filter->pf_vout_buffer_new == VideoBufferNew; + return p_filter->filter.pf_video_buffer_new == VideoBufferNew; } /* */ -static int AllocatorInit( const filter_chain_allocator_t *p_alloc, filter_t *p_filter ) +static int AllocatorInit( const filter_chain_allocator_t *p_alloc, + chained_filter_t *p_filter ) { if( p_alloc->pf_init ) - return p_alloc->pf_init( p_filter, p_alloc->p_data ); + return p_alloc->pf_init( &p_filter->filter, p_alloc->p_data ); return VLC_SUCCESS; } -static void AllocatorClean( const filter_chain_allocator_t *p_alloc, filter_t *p_filter ) + +static void AllocatorClean( const filter_chain_allocator_t *p_alloc, + chained_filter_t *p_filter ) { if( p_alloc->pf_clean ) - p_alloc->pf_clean( p_filter ); + p_alloc->pf_clean( &p_filter->filter ); }