X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvout_subpictures.c;h=45d05414e16870e470c86ec4be329e3b608b38d7;hb=04a5bdf3fb10b76f5c44df4816834fd1cbb60bfd;hp=7a94ad57424f78d4de157e7e42b7bc786de2b4d4;hpb=776b826403cda061217ede59b2d89b26e3dca166;p=vlc diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c index 7a94ad5742..45d05414e1 100644 --- a/src/video_output/vout_subpictures.c +++ b/src/video_output/vout_subpictures.c @@ -37,10 +37,13 @@ #include #include #include -#include +#include #include "../libvlc.h" #include "vout_internal.h" #include +#include +#include +#include "../misc/subpicture.h" /***************************************************************************** * Local prototypes @@ -71,6 +74,7 @@ static void SpuHeapClean( spu_heap_t *p_heap ); struct spu_private_t { vlc_mutex_t lock; /* lock to protect all followings fields */ + vlc_object_t *p_input; spu_heap_t heap; @@ -95,15 +99,6 @@ struct spu_private_t mtime_t i_last_sort_date; }; -/* */ -struct subpicture_region_private_t -{ - video_format_t fmt; - picture_t *p_picture; -}; -static subpicture_region_private_t *SpuRegionPrivateNew( video_format_t * ); -static void SpuRegionPrivateDelete( subpicture_region_private_t * ); - /* */ typedef struct { @@ -143,10 +138,6 @@ static bool spu_area_overlap( spu_area_t, spu_area_t ); #define SCALE_UNIT (1000) -static void SubpictureUpdate( subpicture_t *, - const video_format_t *p_fmt_src, - const video_format_t *p_fmt_dst, - mtime_t i_ts ); static void SubpictureChain( subpicture_t **pp_head, subpicture_t *p_subpic ); static int SubpictureCmp( const void *s0, const void *s1 ); @@ -161,19 +152,19 @@ static void SpuRenderRegion( spu_t *, static void UpdateSPU ( spu_t *, vlc_object_t * ); static int CropCallback( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * ); -static int MarginCallback( vlc_object_t *, char const *, - vlc_value_t, vlc_value_t, void * ); /* Buffer allocation for SPU filter (blend, scale, ...) */ -static subpicture_t *spu_new_buffer( filter_t * ); -static void spu_del_buffer( filter_t *, subpicture_t * ); +struct filter_owner_sys_t +{ + spu_t *p_spu; + int i_channel; +}; +static int spu_get_attachments( filter_t *, + input_attachment_t ***, int * ); static picture_t *spu_new_video_buffer( filter_t * ); static void spu_del_video_buffer( filter_t *, picture_t * ); /* Buffer aloccation fir SUB filter */ -static int SubFilterCallback( vlc_object_t *, char const *, - vlc_value_t, vlc_value_t, void * ); - static int SubFilterAllocationInit( filter_t *, void * ); static void SubFilterAllocationClean( filter_t * ); @@ -219,7 +210,7 @@ spu_t *spu_Create( vlc_object_t *p_this ) p_sys->i_margin = var_InheritInteger( p_spu, "sub-margin" ); /* Register the default subpicture channel */ - p_sys->i_channel = 2; + p_sys->i_channel = SPU_DEFAULT_CHANNEL + 1; p_sys->psz_chain_update = NULL; vlc_mutex_init( &p_sys->chain_lock ); @@ -238,20 +229,6 @@ spu_t *spu_Create( vlc_object_t *p_this ) return p_spu; } -/** - * Initialise the subpicture unit - * - * \param p_spu the subpicture unit object - */ -int spu_Init( spu_t *p_spu ) -{ - var_Create( p_spu, "sub-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); - var_AddCallback( p_spu, "sub-filter", SubFilterCallback, p_spu ); - var_TriggerCallback( p_spu, "sub-filter" ); - - return VLC_SUCCESS; -} - /** * Destroy the subpicture unit * @@ -261,8 +238,6 @@ void spu_Destroy( spu_t *p_spu ) { spu_private_t *p_sys = p_spu->p; - var_DelCallback( p_spu, "sub-filter", SubFilterCallback, p_spu ); - if( p_sys->p_blend ) filter_DeleteBlend( p_sys->p_blend ); @@ -293,34 +268,32 @@ void spu_Destroy( spu_t *p_spu ) * \param p_this the object in which to destroy the subpicture unit * \param b_attach to select attach or detach */ -void spu_Attach( spu_t *p_spu, vlc_object_t *p_this, bool b_attach ) +void spu_Attach( spu_t *p_spu, vlc_object_t *p_input, bool b_attach ) { - vlc_object_t *p_input; - - p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT ); - if( !p_input ) - return; - if( b_attach ) { - UpdateSPU( p_spu, VLC_OBJECT(p_input) ); + UpdateSPU( p_spu, p_input ); var_Create( p_input, "highlight", VLC_VAR_BOOL ); var_AddCallback( p_input, "highlight", CropCallback, p_spu ); - var_AddCallback( p_input, "sub-margin", MarginCallback, p_spu->p ); vlc_mutex_lock( &p_spu->p->lock ); - p_spu->p->i_margin = var_GetInteger( p_input, "sub-margin" ); - vlc_mutex_unlock( &p_spu->p->lock ); + p_spu->p->p_input = p_input; + + FilterRelease( p_spu->p->p_text ); + p_spu->p->p_text = NULL; + SpuRenderCreateAndLoadText( p_spu ); - vlc_object_release( p_input ); + vlc_mutex_unlock( &p_spu->p->lock ); } else { + vlc_mutex_lock( &p_spu->p->lock ); + p_spu->p->p_input = NULL; + vlc_mutex_unlock( &p_spu->p->lock ); + /* Delete callbacks */ - var_DelCallback( p_input, "sub-margin", MarginCallback, p_spu->p ); var_DelCallback( p_input, "highlight", CropCallback, p_spu ); var_Destroy( p_input, "highlight" ); - vlc_object_release( p_input ); } } @@ -405,9 +378,9 @@ void spu_RenderSubpictures( spu_t *p_spu, p_subpic != NULL; p_subpic = p_subpic->p_next ) { - SubpictureUpdate( p_subpic, - p_fmt_src, p_fmt_dst, - p_subpic->b_subtitle ? render_subtitle_date : render_osd_date ); + subpicture_Update( p_subpic, + p_fmt_src, p_fmt_dst, + p_subpic->b_subtitle ? render_subtitle_date : render_osd_date ); /* */ if( p_subpic->b_subtitle ) @@ -556,7 +529,6 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t render_subtitle_date, bool b_subtitle_only ) { spu_private_t *p_sys = p_spu->p; - int i_channel; subpicture_t *p_subpic = NULL; const mtime_t render_osd_date = mdate(); @@ -581,10 +553,31 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t render_subtitle_date, vlc_mutex_lock( &p_sys->lock ); + /* Create a list of channels */ + int pi_channel[VOUT_MAX_SUBPICTURES]; + int i_channel_count = 0; + + for( int i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ ) + { + spu_heap_entry_t *p_entry = &p_sys->heap.p_entry[i_index]; + if( !p_entry->p_subpicture || p_entry->b_reject ) + continue; + const int i_channel = p_entry->p_subpicture->i_channel; + int i; + for( i = 0; i < i_channel_count; i++ ) + { + if( pi_channel[i] == i_channel ) + break; + } + if( i_channel_count <= i ) + pi_channel[i_channel_count++] = i_channel; + } + /* We get an easily parsable chained list of subpictures which * ends with NULL since p_subpic was initialized to NULL. */ - for( i_channel = 0; i_channel < p_sys->i_channel; i_channel++ ) + for( int i = 0; i < i_channel_count; i++ ) { + const int i_channel = pi_channel[i]; subpicture_t *p_available_subpic[VOUT_MAX_SUBPICTURES]; bool pb_available_late[VOUT_MAX_SUBPICTURES]; int i_available = 0; @@ -744,66 +737,28 @@ void spu_ClearChannel( spu_t *p_spu, int i_channel ) vlc_mutex_unlock( &p_sys->lock ); } -/***************************************************************************** - * subpicture_t allocation - *****************************************************************************/ -struct subpicture_private_t +void spu_ChangeFilters( spu_t *p_spu, const char *psz_filters ) { - video_format_t src; - video_format_t dst; -}; - -subpicture_t *subpicture_New( const subpicture_updater_t *p_upd ) -{ - subpicture_t *p_subpic = calloc( 1, sizeof(*p_subpic) ); - if( !p_subpic ) - return NULL; - - p_subpic->i_order = 0; - p_subpic->b_absolute = true; - p_subpic->b_fade = false; - p_subpic->b_subtitle = false; - p_subpic->i_alpha = 0xFF; - p_subpic->p_region = NULL; + spu_private_t *p_sys = p_spu->p; - if( p_upd ) - { - subpicture_private_t *p_private = malloc( sizeof(*p_private) ); - if( !p_private ) - { - free( p_subpic ); - return NULL; - } - video_format_Init( &p_private->src, 0 ); - video_format_Init( &p_private->dst, 0 ); + vlc_mutex_lock( &p_sys->lock ); - p_subpic->updater = *p_upd; - p_subpic->p_private = p_private; - } - else - { - p_subpic->p_private = NULL; + free( p_sys->psz_chain_update ); + p_sys->psz_chain_update = strdup( psz_filters ); - p_subpic->updater.pf_validate = NULL; - p_subpic->updater.pf_update = NULL; - p_subpic->updater.pf_destroy = NULL; - p_subpic->updater.p_sys = NULL; - } - return p_subpic; + vlc_mutex_unlock( &p_sys->lock ); } -void subpicture_Delete( subpicture_t *p_subpic ) +void spu_ChangeMargin( spu_t *p_spu, int i_margin ) { - subpicture_region_ChainDelete( p_subpic->p_region ); - p_subpic->p_region = NULL; - - if( p_subpic->updater.pf_destroy ) - p_subpic->updater.pf_destroy( p_subpic ); + spu_private_t *p_sys = p_spu->p; - free( p_subpic->p_private ); - free( p_subpic ); + vlc_mutex_lock( &p_sys->lock ); + p_sys->i_margin = i_margin; + vlc_mutex_unlock( &p_sys->lock ); } +/* */ static void SubpictureChain( subpicture_t **pp_head, subpicture_t *p_subpic ) { p_subpic->p_next = *pp_head; @@ -811,159 +766,6 @@ static void SubpictureChain( subpicture_t **pp_head, subpicture_t *p_subpic ) *pp_head = p_subpic; } -subpicture_t *subpicture_NewFromPicture( vlc_object_t *p_obj, - picture_t *p_picture, vlc_fourcc_t i_chroma ) -{ - /* */ - video_format_t fmt_in = p_picture->format; - - /* */ - video_format_t fmt_out; - fmt_out = fmt_in; - fmt_out.i_chroma = i_chroma; - - /* */ - image_handler_t *p_image = image_HandlerCreate( p_obj ); - if( !p_image ) - return NULL; - - picture_t *p_pip = image_Convert( p_image, p_picture, &fmt_in, &fmt_out ); - - image_HandlerDelete( p_image ); - - if( !p_pip ) - return NULL; - - subpicture_t *p_subpic = subpicture_New( NULL ); - if( !p_subpic ) - { - picture_Release( p_pip ); - return NULL; - } - - p_subpic->i_original_picture_width = fmt_out.i_width; - p_subpic->i_original_picture_height = fmt_out.i_height; - - fmt_out.i_sar_num = - fmt_out.i_sar_den = 0; - - p_subpic->p_region = subpicture_region_New( &fmt_out ); - if( p_subpic->p_region ) - { - picture_Release( p_subpic->p_region->p_picture ); - p_subpic->p_region->p_picture = p_pip; - } - else - { - picture_Release( p_pip ); - } - return p_subpic; -} - -static void SubpictureUpdate( subpicture_t *p_subpicture, - const video_format_t *p_fmt_src, - const video_format_t *p_fmt_dst, - mtime_t i_ts ) -{ - subpicture_updater_t *p_upd = &p_subpicture->updater; - subpicture_private_t *p_private = p_subpicture->p_private; - - if( !p_upd->pf_validate ) - return; - if( !p_upd->pf_validate( p_subpicture, - !video_format_IsSimilar( p_fmt_src, - &p_private->src ), p_fmt_src, - !video_format_IsSimilar( p_fmt_dst, - &p_private->dst ), p_fmt_dst, - i_ts ) ) - return; - - subpicture_region_ChainDelete( p_subpicture->p_region ); - p_subpicture->p_region = NULL; - - p_upd->pf_update( p_subpicture, p_fmt_src, p_fmt_dst, i_ts ); - - video_format_Clean( &p_private->src ); - video_format_Clean( &p_private->dst ); - - video_format_Copy( &p_private->src, p_fmt_src ); - video_format_Copy( &p_private->dst, p_fmt_dst ); -} - -/***************************************************************************** - * subpicture_region_t allocation - *****************************************************************************/ -subpicture_region_t *subpicture_region_New( const video_format_t *p_fmt ) -{ - subpicture_region_t *p_region = calloc( 1, sizeof(*p_region ) ); - if( !p_region ) - return NULL; - - p_region->fmt = *p_fmt; - p_region->fmt.p_palette = NULL; - if( p_fmt->i_chroma == VLC_CODEC_YUVP ) - { - p_region->fmt.p_palette = calloc( 1, sizeof(*p_region->fmt.p_palette) ); - if( p_fmt->p_palette ) - *p_region->fmt.p_palette = *p_fmt->p_palette; - } - p_region->i_alpha = 0xff; - p_region->p_next = NULL; - p_region->p_private = NULL; - p_region->psz_text = NULL; - p_region->p_style = NULL; - p_region->p_picture = NULL; - - if( p_fmt->i_chroma == VLC_CODEC_TEXT ) - return p_region; - - p_region->p_picture = picture_NewFromFormat( p_fmt ); - if( !p_region->p_picture ) - { - free( p_region->fmt.p_palette ); - free( p_region ); - return NULL; - } - - return p_region; -} - -/* */ -void subpicture_region_Delete( subpicture_region_t *p_region ) -{ - if( !p_region ) - return; - - if( p_region->p_private ) - SpuRegionPrivateDelete( p_region->p_private ); - - if( p_region->p_picture ) - picture_Release( p_region->p_picture ); - - free( p_region->fmt.p_palette ); - - free( p_region->psz_text ); - free( p_region->psz_html ); - if( p_region->p_style ) - text_style_Delete( p_region->p_style ); - free( p_region ); -} - -/* */ -void subpicture_region_ChainDelete( subpicture_region_t *p_head ) -{ - while( p_head ) - { - subpicture_region_t *p_next = p_head->p_next; - - subpicture_region_Delete( p_head ); - - p_head = p_next; - } -} - - - /***************************************************************************** * heap managment *****************************************************************************/ @@ -1029,36 +831,12 @@ static void SpuHeapClean( spu_heap_t *p_heap ) } } -static subpicture_region_private_t *SpuRegionPrivateNew( video_format_t *p_fmt ) -{ - subpicture_region_private_t *p_private = malloc( sizeof(*p_private) ); - - if( !p_private ) - return NULL; - - p_private->fmt = *p_fmt; - if( p_fmt->p_palette ) - { - p_private->fmt.p_palette = malloc( sizeof(*p_private->fmt.p_palette) ); - if( p_private->fmt.p_palette ) - *p_private->fmt.p_palette = *p_fmt->p_palette; - } - p_private->p_picture = NULL; - - return p_private; -} -static void SpuRegionPrivateDelete( subpicture_region_private_t *p_private ) -{ - if( p_private->p_picture ) - picture_Release( p_private->p_picture ); - free( p_private->fmt.p_palette ); - free( p_private ); -} - static void FilterRelease( filter_t *p_filter ) { if( p_filter->p_module ) module_unneed( p_filter, p_filter->p_module ); + if( p_filter->p_owner ) + free( p_filter->p_owner ); vlc_object_release( p_filter ); } @@ -1075,6 +853,9 @@ static void SpuRenderCreateAndLoadText( spu_t *p_spu ) if( !p_text ) return; + p_text->p_owner = xmalloc( sizeof(*p_text->p_owner) ); + p_text->p_owner->p_spu = p_spu; + es_format_Init( &p_text->fmt_in, VIDEO_ES, 0 ); es_format_Init( &p_text->fmt_out, VIDEO_ES, 0 ); @@ -1083,8 +864,7 @@ static void SpuRenderCreateAndLoadText( spu_t *p_spu ) p_text->fmt_out.video.i_height = p_text->fmt_out.video.i_visible_height = 32; - p_text->pf_sub_buffer_new = spu_new_buffer; - p_text->pf_sub_buffer_del = spu_del_buffer; + p_text->pf_get_attachments = spu_get_attachments; vlc_object_attach( p_text, p_spu ); @@ -1404,25 +1184,6 @@ static void SpuRegionPlace( int *pi_x, int *pi_y, i_y = i_delta_y; } - /* Margin shifts all subpictures */ - /* NOTE We have margin only for subtitles, so we don't really need this here - if( i_margin_y != 0 ) - i_y -= i_margin_y;*/ - - /* Clamp offset to not go out of the screen (when possible) */ - /* NOTE Again, useful only for subtitles, otherwise goes against the alignment logic above - const int i_error_x = (i_x + p_region->fmt.i_width) - p_subpic->i_original_picture_width; - if( i_error_x > 0 ) - i_x -= i_error_x; - if( i_x < 0 ) - i_x = 0; - - const int i_error_y = (i_y + p_region->fmt.i_height) - p_subpic->i_original_picture_height; - if( i_error_y > 0 ) - i_y -= i_error_y; - if( i_y < 0 ) - i_y = 0;*/ - *pi_x = i_x; *pi_y = i_y; } @@ -1529,12 +1290,11 @@ static void SpuRenderRegion( spu_t *p_spu, /* apply margin to subtitles and correct if they go over the picture edge */ if( p_subpic->b_subtitle ) - { restrained.i_y -= i_margin_y; - spu_area_t display = spu_area_create( 0, 0, p_fmt->i_width, p_fmt->i_height, - spu_scale_unit() ); - SpuAreaFitInside( &restrained, &display ); - } + + spu_area_t display = spu_area_create( 0, 0, p_fmt->i_width, p_fmt->i_height, + spu_scale_unit() ); + SpuAreaFitInside( &restrained, &display ); /* Fix the position for the current scale_size */ i_x_offset = spu_scale_w( restrained.i_x, restrained.scale ); @@ -1595,7 +1355,7 @@ static void SpuRenderRegion( spu_t *p_spu, if( b_changed ) { - SpuRegionPrivateDelete( p_private ); + subpicture_region_private_Delete( p_private ); p_region->p_private = NULL; } } @@ -1653,13 +1413,13 @@ static void SpuRenderRegion( spu_t *p_spu, /* */ if( p_picture ) { - p_region->p_private = SpuRegionPrivateNew( &p_picture->format ); + p_region->p_private = subpicture_region_private_New( &p_picture->format ); if( p_region->p_private ) { p_region->p_private->p_picture = p_picture; if( !p_region->p_private->p_picture ) { - SpuRegionPrivateDelete( p_region->p_private ); + subpicture_region_private_Delete( p_region->p_private ); p_region->p_private = NULL; } } @@ -1744,7 +1504,7 @@ exit: } if( p_region->p_private ) { - SpuRegionPrivateDelete( p_region->p_private ); + subpicture_region_private_Delete( p_region->p_private ); p_region->p_private = NULL; } p_region->i_align &= ~SUBPICTURE_RENDERED; @@ -1847,30 +1607,22 @@ static int CropCallback( vlc_object_t *p_object, char const *psz_var, return VLC_SUCCESS; } -/***************************************************************************** - * MarginCallback: called when requested subtitle position has changed * - *****************************************************************************/ - -static int MarginCallback( vlc_object_t *p_object, char const *psz_var, - vlc_value_t oldval, vlc_value_t newval, void *p_data ) -{ - VLC_UNUSED( psz_var ); VLC_UNUSED( oldval ); VLC_UNUSED( p_object ); - spu_private_t *p_sys = ( spu_private_t* ) p_data; - - vlc_mutex_lock( &p_sys->lock ); - p_sys->i_margin = newval.i_int; - vlc_mutex_unlock( &p_sys->lock ); - return VLC_SUCCESS; -} - /***************************************************************************** * Buffers allocation callbacks for the filters *****************************************************************************/ -struct filter_owner_sys_t -{ - spu_t *p_spu; - int i_channel; -}; +static int spu_get_attachments( filter_t *p_filter, + input_attachment_t ***ppp_attachment, + int *pi_attachment ) +{ + spu_t *p_spu = p_filter->p_owner->p_spu; + + int i_ret = VLC_EGENERIC; + if( p_spu->p->p_input ) + i_ret = input_Control( (input_thread_t*)p_spu->p->p_input, + INPUT_GET_ATTACHMENTS, + ppp_attachment, pi_attachment ); + return i_ret; +} static subpicture_t *sub_new_buffer( filter_t *p_filter ) { @@ -1886,18 +1638,6 @@ static void sub_del_buffer( filter_t *p_filter, subpicture_t *p_subpic ) VLC_UNUSED( p_filter ); subpicture_Delete( p_subpic ); } - -static subpicture_t *spu_new_buffer( filter_t *p_filter ) -{ - VLC_UNUSED(p_filter); - return subpicture_New( NULL ); -} -static void spu_del_buffer( filter_t *p_filter, subpicture_t *p_subpic ) -{ - VLC_UNUSED(p_filter); - subpicture_Delete( p_subpic ); -} - static picture_t *spu_new_video_buffer( filter_t *p_filter ) { const video_format_t *p_fmt = &p_filter->fmt_out.video; @@ -1937,20 +1677,3 @@ static void SubFilterAllocationClean( filter_t *p_filter ) free( p_filter->p_owner ); } -static int SubFilterCallback( vlc_object_t *p_object, char const *psz_var, - vlc_value_t oldval, vlc_value_t newval, void *p_data ) -{ - spu_t *p_spu = p_data; - spu_private_t *p_sys = p_spu->p; - - VLC_UNUSED(p_object); VLC_UNUSED(oldval); VLC_UNUSED(psz_var); - - vlc_mutex_lock( &p_sys->lock ); - - free( p_sys->psz_chain_update ); - p_sys->psz_chain_update = strdup( newval.psz_string ); - - vlc_mutex_unlock( &p_sys->lock ); - return VLC_SUCCESS; -} -