X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvout_subpictures.c;h=12814124b34baeee2b9c8c08ddd4d934cb2f418b;hb=355e0a3776c72500f16f9d6cccc28682c812969b;hp=4f12c37b55cac7c963807f3daf7c20988704f227;hpb=1185b8970aeddc1d1dbaf76c22d0fb36a440dedf;p=vlc diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c index 4f12c37b55..12814124b3 100644 --- a/src/video_output/vout_subpictures.c +++ b/src/video_output/vout_subpictures.c @@ -1,7 +1,7 @@ /***************************************************************************** * vout_subpictures.c : subpicture management functions ***************************************************************************** - * Copyright (C) 2000-2004 VideoLAN + * Copyright (C) 2000-2005 the VideoLAN team * $Id$ * * Authors: Vincent Seguin @@ -20,7 +20,7 @@ * * 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. *****************************************************************************/ /***************************************************************************** @@ -35,108 +35,206 @@ #include "vlc_block.h" #include "vlc_video.h" #include "video_output.h" +#include "vlc_spu.h" #include "vlc_filter.h" -#include "osd.h" -static void UpdateSPU ( vout_thread_t *, vlc_object_t * ); -static int CropCallback ( vlc_object_t *, char const *, - vlc_value_t, vlc_value_t, void * ); +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +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 spu_vaControlDefault( spu_t *, int, va_list ); + +static subpicture_t *sub_new_buffer( filter_t * ); +static void sub_del_buffer( filter_t *, subpicture_t * ); static subpicture_t *spu_new_buffer( filter_t * ); static void spu_del_buffer( filter_t *, subpicture_t * ); +static picture_t *spu_new_video_buffer( filter_t * ); +static void spu_del_video_buffer( filter_t *, picture_t * ); + +struct filter_owner_sys_t +{ + spu_t *p_spu; + int i_channel; +}; /** - * Initialise the subpicture decoder unit + * Creates the subpicture unit * - * \param p_vout the vout in which to create the subpicture unit + * \param p_this the parent object which creates the subpicture unit */ -void vout_InitSPU( vout_thread_t *p_vout ) +spu_t *__spu_Create( vlc_object_t *p_this ) { int i_index; + spu_t *p_spu = vlc_object_create( p_this, VLC_OBJECT_SPU ); for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++) { - p_vout->p_subpicture[i_index].i_status = FREE_SUBPICTURE; - p_vout->p_subpicture[i_index].i_type = EMPTY_SUBPICTURE; + p_spu->p_subpicture[i_index].i_status = FREE_SUBPICTURE; } - p_vout->p_blend = NULL; - p_vout->p_text = NULL; + p_spu->p_blend = NULL; + p_spu->p_text = NULL; + p_spu->p_scale = NULL; + p_spu->i_filter = 0; + p_spu->pf_control = spu_vaControlDefault; + + /* Register the default subpicture channel */ + p_spu->i_channel = 2; + + vlc_mutex_init( p_this, &p_spu->subpicture_lock ); + + vlc_object_attach( p_spu, p_this ); + + return p_spu; +} + +/** + * Initialise the subpicture unit + * + * \param p_spu the subpicture unit object + */ +int spu_Init( spu_t *p_spu ) +{ + char *psz_filter, *psz_filter_orig; + vlc_value_t val; + + /* If the user requested a sub margin, we force the position. */ + var_Create( p_spu, "sub-margin", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); + var_Get( p_spu, "sub-margin", &val ); + p_spu->i_margin = val.i_int; + + var_Create( p_spu, "sub-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); + var_Get( p_spu, "sub-filter", &val ); + psz_filter = psz_filter_orig = val.psz_string; + while( psz_filter && *psz_filter ) + { + char *psz_parser = strchr( psz_filter, ':' ); + + if( psz_parser ) *psz_parser++ = 0; + + p_spu->pp_filter[p_spu->i_filter] = + vlc_object_create( p_spu, VLC_OBJECT_FILTER ); + vlc_object_attach( p_spu->pp_filter[p_spu->i_filter], p_spu ); + p_spu->pp_filter[p_spu->i_filter]->pf_sub_buffer_new = sub_new_buffer; + p_spu->pp_filter[p_spu->i_filter]->pf_sub_buffer_del = sub_del_buffer; + p_spu->pp_filter[p_spu->i_filter]->p_module = + module_Need( p_spu->pp_filter[p_spu->i_filter], + "sub filter", psz_filter, 0 ); + if( p_spu->pp_filter[p_spu->i_filter]->p_module ) + { + filter_owner_sys_t *p_sys = malloc( sizeof(filter_owner_sys_t) ); + p_spu->pp_filter[p_spu->i_filter]->p_owner = p_sys; + spu_Control( p_spu, SPU_CHANNEL_REGISTER, &p_sys->i_channel ); + p_sys->p_spu = p_spu; + p_spu->i_filter++; + } + else + { + msg_Dbg( p_spu, "no sub filter found" ); + vlc_object_detach( p_spu->pp_filter[p_spu->i_filter] ); + vlc_object_destroy( p_spu->pp_filter[p_spu->i_filter] ); + } + + if( p_spu->i_filter >= 10 ) + { + msg_Dbg( p_spu, "can't add anymore filters" ); + } - p_vout->i_crop_x = p_vout->i_crop_y = - p_vout->i_crop_width = p_vout->i_crop_height = 0; - p_vout->b_force_alpha = VLC_FALSE; - p_vout->b_force_crop = VLC_FALSE; + psz_filter = psz_parser; + } + if( psz_filter_orig ) free( psz_filter_orig ); - vout_AttachSPU( p_vout, VLC_TRUE ); + return VLC_EGENERIC; } /** - * Destroy the subpicture decoder unit + * Destroy the subpicture unit * - * \param p_vout the vout in which to destroy the subpicture unit + * \param p_this the parent object which destroys the subpicture unit */ -void vout_DestroySPU( vout_thread_t *p_vout ) +void spu_Destroy( spu_t *p_spu ) { int i_index; + vlc_object_detach( p_spu ); + /* Destroy all remaining subpictures */ for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ ) { - if( p_vout->p_subpicture[i_index].i_status != FREE_SUBPICTURE ) + if( p_spu->p_subpicture[i_index].i_status != FREE_SUBPICTURE ) { - vout_DestroySubPicture( p_vout, - &p_vout->p_subpicture[i_index] ); + spu_DestroySubpicture( p_spu, &p_spu->p_subpicture[i_index] ); } } - if( p_vout->p_blend ) + if( p_spu->p_blend ) { - if( p_vout->p_blend->p_module ) - module_Unneed( p_vout->p_blend, p_vout->p_blend->p_module ); + if( p_spu->p_blend->p_module ) + module_Unneed( p_spu->p_blend, p_spu->p_blend->p_module ); - vlc_object_detach( p_vout->p_blend ); - vlc_object_destroy( p_vout->p_blend ); + vlc_object_detach( p_spu->p_blend ); + vlc_object_destroy( p_spu->p_blend ); } - if( p_vout->p_text ) + if( p_spu->p_text ) { - if( p_vout->p_text->p_module ) - module_Unneed( p_vout->p_text, p_vout->p_text->p_module ); + if( p_spu->p_text->p_module ) + module_Unneed( p_spu->p_text, p_spu->p_text->p_module ); + + vlc_object_detach( p_spu->p_text ); + vlc_object_destroy( p_spu->p_text ); + } + + if( p_spu->p_scale ) + { + if( p_spu->p_scale->p_module ) + module_Unneed( p_spu->p_scale, p_spu->p_scale->p_module ); + + vlc_object_detach( p_spu->p_scale ); + vlc_object_destroy( p_spu->p_scale ); + } - vlc_object_detach( p_vout->p_text ); - vlc_object_destroy( p_vout->p_text ); + while( p_spu->i_filter-- ) + { + module_Unneed( p_spu->pp_filter[p_spu->i_filter], + p_spu->pp_filter[p_spu->i_filter]->p_module ); + free( p_spu->pp_filter[p_spu->i_filter]->p_owner ); + vlc_object_detach( p_spu->pp_filter[p_spu->i_filter] ); + vlc_object_destroy( p_spu->pp_filter[p_spu->i_filter] ); } - vout_AttachSPU( p_vout, VLC_FALSE ); + vlc_mutex_destroy( &p_spu->subpicture_lock ); + vlc_object_destroy( p_spu ); } /** * Attach/Detach the SPU from any input * - * \param p_vout the vout in which to destroy the subpicture unit + * \param p_this the object in which to destroy the subpicture unit * \param b_attach to select attach or detach */ -void vout_AttachSPU( vout_thread_t *p_vout, vlc_bool_t b_attach ) +void spu_Attach( spu_t *p_spu, vlc_object_t *p_this, vlc_bool_t b_attach ) { vlc_object_t *p_input; - p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT ); + p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT ); if( !p_input ) return; if( b_attach ) { - UpdateSPU( p_vout, VLC_OBJECT(p_input) ); - var_AddCallback( p_input, "highlight", CropCallback, p_vout ); + UpdateSPU( p_spu, VLC_OBJECT(p_input) ); + var_AddCallback( p_input, "highlight", CropCallback, p_spu ); vlc_object_release( p_input ); } else { /* Delete callback */ - var_DelCallback( p_input, "highlight", CropCallback, p_vout ); + var_DelCallback( p_input, "highlight", CropCallback, p_spu ); vlc_object_release( p_input ); } - } /** @@ -145,21 +243,27 @@ void vout_AttachSPU( vout_thread_t *p_vout, vlc_bool_t b_attach ) * \param p_this vlc_object_t * \param p_fmt the format that this subpicture region should have */ +static void RegionPictureRelease( picture_t *p_pic ) +{ + if( p_pic->p_data_orig ) free( p_pic->p_data_orig ); +} subpicture_region_t *__spu_CreateRegion( vlc_object_t *p_this, video_format_t *p_fmt ) { subpicture_region_t *p_region = malloc( sizeof(subpicture_region_t) ); memset( p_region, 0, sizeof(subpicture_region_t) ); p_region->p_next = 0; + p_region->p_cache = 0; p_region->fmt = *p_fmt; p_region->psz_text = 0; + p_region->i_text_color = 0xFFFFFF; if( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) p_fmt->p_palette = p_region->fmt.p_palette = malloc( sizeof(video_palette_t) ); else p_fmt->p_palette = p_region->fmt.p_palette = NULL; - p_region->picture.p_data_orig = 0; + p_region->picture.p_data_orig = NULL; if( p_fmt->i_chroma == VLC_FOURCC('T','E','X','T') ) return p_region; @@ -173,6 +277,38 @@ subpicture_region_t *__spu_CreateRegion( vlc_object_t *p_this, return NULL; } + p_region->picture.pf_release = RegionPictureRelease; + + return p_region; +} + +/** + * Make a subpicture region from an existing picture_t + * + * \param p_this vlc_object_t + * \param p_fmt the format that this subpicture region should have + * \param p_pic a pointer to the picture creating the region (not freed) + */ +subpicture_region_t *__spu_MakeRegion( vlc_object_t *p_this, + video_format_t *p_fmt, + picture_t *p_pic ) +{ + subpicture_region_t *p_region = malloc( sizeof(subpicture_region_t) ); + memset( p_region, 0, sizeof(subpicture_region_t) ); + p_region->p_next = 0; + p_region->p_cache = 0; + p_region->fmt = *p_fmt; + p_region->psz_text = 0; + p_region->i_text_color = 0xFFFFFF; + + if( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) + p_fmt->p_palette = p_region->fmt.p_palette = + malloc( sizeof(video_palette_t) ); + else p_fmt->p_palette = p_region->fmt.p_palette = NULL; + + memcpy( &p_region->picture, p_pic, sizeof(picture_t) ); + p_region->picture.pf_release = RegionPictureRelease; + return p_region; } @@ -185,75 +321,59 @@ subpicture_region_t *__spu_CreateRegion( vlc_object_t *p_this, void __spu_DestroyRegion( vlc_object_t *p_this, subpicture_region_t *p_region ) { if( !p_region ) return; - if( p_region->picture.p_data_orig ) free( p_region->picture.p_data_orig ); + if( p_region->picture.pf_release ) + p_region->picture.pf_release( &p_region->picture ); if( p_region->fmt.p_palette ) free( p_region->fmt.p_palette ); if( p_region->psz_text ) free( p_region->psz_text ); + if( p_region->p_cache ) __spu_DestroyRegion( p_this, p_region->p_cache ); free( p_region ); } /** - * Display a subpicture unit + * Display a subpicture * * Remove the reservation flag of a subpicture, which will cause it to be * ready for display. - * \param p_vout the video output this subpicture should be displayed on + * \param p_spu the subpicture unit object * \param p_subpic the subpicture to display */ -void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) +void spu_DisplaySubpicture( spu_t *p_spu, subpicture_t *p_subpic ) { - int i_margin; - /* Check if status is valid */ if( p_subpic->i_status != RESERVED_SUBPICTURE ) { - msg_Err( p_vout, "subpicture %p has invalid status #%d", - p_subpic, p_subpic->i_status ); + msg_Err( p_spu, "subpicture %p has invalid status #%d", + p_subpic, p_subpic->i_status ); } - /* If the user requested an SPU margin, we force the position after - * having checked that it was a valid value. */ - i_margin = config_GetInt( p_vout, "spumargin" ); + /* Remove reservation flag */ + p_subpic->i_status = READY_SUBPICTURE; - if( i_margin >= 0 ) + if( p_subpic->i_channel == DEFAULT_CHAN ) { - if( p_subpic->i_height + (unsigned int)i_margin - <= p_vout->output.i_height ) - { - p_subpic->i_y = p_vout->output.i_height - - i_margin - p_subpic->i_height; - } + p_subpic->i_channel = 0xFFFF; + spu_Control( p_spu, SPU_CHANNEL_CLEAR, DEFAULT_CHAN ); + p_subpic->i_channel = DEFAULT_CHAN; } - - /* Remove reservation flag */ - p_subpic->i_status = READY_SUBPICTURE; } /** - * Allocate a subpicture in the video output heap. + * Allocate a subpicture in the spu heap. * - * This function create a reserved subpicture in the video output heap. + * This function create a reserved subpicture in the spu heap. * A null pointer is returned if the function fails. This method provides an * already allocated zone of memory in the spu data fields. It needs locking * since several pictures can be created by several producers threads. - * \param p_vout the vout in which to create the subpicture - * \param i_channel the channel this subpicture should belong to - * \param i_type the type of the subpicture + * \param p_spu the subpicture unit in which to create the subpicture * \return NULL on error, a reserved subpicture otherwise */ -subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_channel, - int i_type ) +subpicture_t *spu_CreateSubpicture( spu_t *p_spu ) { int i_subpic; /* subpicture index */ subpicture_t * p_subpic = NULL; /* first free subpicture */ - /* Clear the default channel before writing into it */ - if( i_channel == DEFAULT_CHAN ) - { - vout_ClearOSDChannel( p_vout, DEFAULT_CHAN ); - } - /* Get lock */ - vlc_mutex_lock( &p_vout->subpicture_lock ); + vlc_mutex_lock( &p_spu->subpicture_lock ); /* * Look for an empty place @@ -261,11 +381,11 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_channel, p_subpic = NULL; for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ ) { - if( p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ) + if( p_spu->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ) { /* Subpicture is empty and ready for allocation */ - p_subpic = &p_vout->p_subpicture[i_subpic]; - p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE; + p_subpic = &p_spu->p_subpicture[i_subpic]; + p_spu->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE; break; } } @@ -273,41 +393,27 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_channel, /* If no free subpicture could be found */ if( p_subpic == NULL ) { - msg_Err( p_vout, "subpicture heap is full" ); - vlc_mutex_unlock( &p_vout->subpicture_lock ); + msg_Err( p_spu, "subpicture heap is full" ); + vlc_mutex_unlock( &p_spu->subpicture_lock ); return NULL; } /* Copy subpicture information, set some default values */ - p_subpic->i_channel = i_channel; - p_subpic->i_type = i_type; - p_subpic->i_status = RESERVED_SUBPICTURE; - - p_subpic->i_start = 0; - p_subpic->i_stop = 0; - p_subpic->b_ephemer = VLC_FALSE; - - p_subpic->i_x = 0; - p_subpic->i_y = 0; - p_subpic->i_width = 0; - p_subpic->i_height = 0; - p_subpic->b_absolute= VLC_TRUE; - p_subpic->i_flags = 0; - p_subpic->pf_render = 0; - p_subpic->pf_destroy= 0; - p_subpic->p_sys = 0; - - /* Remain last subpicture displayed in DEFAULT_CHAN */ - if( i_channel == DEFAULT_CHAN ) - { - p_vout->p_default_channel = p_subpic; - } - - vlc_mutex_unlock( &p_vout->subpicture_lock ); + memset( p_subpic, 0, sizeof(subpicture_t) ); + p_subpic->i_status = RESERVED_SUBPICTURE; + p_subpic->b_absolute = VLC_TRUE; + p_subpic->b_fade = VLC_FALSE; + p_subpic->i_alpha = 0xFF; + p_subpic->p_region = 0; + p_subpic->pf_render = 0; + p_subpic->pf_destroy = 0; + p_subpic->p_sys = 0; + vlc_mutex_unlock( &p_spu->subpicture_lock ); p_subpic->pf_create_region = __spu_CreateRegion; + p_subpic->pf_make_region = __spu_MakeRegion; p_subpic->pf_destroy_region = __spu_DestroyRegion; - + return p_subpic; } @@ -317,17 +423,17 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_channel, * This function frees a previously reserved subpicture. * It is meant to be used when the construction of a picture aborted. * This function does not need locking since reserved subpictures are ignored - * by the output thread. + * by the spu. */ -void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) +void spu_DestroySubpicture( spu_t *p_spu, subpicture_t *p_subpic ) { /* Get lock */ - vlc_mutex_lock( &p_vout->subpicture_lock ); + vlc_mutex_lock( &p_spu->subpicture_lock ); /* There can be race conditions so we need to check the status */ if( p_subpic->i_status == FREE_SUBPICTURE ) { - vlc_mutex_unlock( &p_vout->subpicture_lock ); + vlc_mutex_unlock( &p_spu->subpicture_lock ); return; } @@ -335,7 +441,7 @@ void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) if( ( p_subpic->i_status != RESERVED_SUBPICTURE ) && ( p_subpic->i_status != READY_SUBPICTURE ) ) { - msg_Err( p_vout, "subpicture %p has invalid status %d", + msg_Err( p_spu, "subpicture %p has invalid status %d", p_subpic, p_subpic->i_status ); } @@ -343,7 +449,7 @@ void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) { subpicture_region_t *p_region = p_subpic->p_region; p_subpic->p_region = p_region->p_next; - spu_DestroyRegion( p_vout, p_region ); + spu_DestroyRegion( p_spu, p_region ); } if( p_subpic->pf_destroy ) @@ -353,151 +459,271 @@ void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) p_subpic->i_status = FREE_SUBPICTURE; - vlc_mutex_unlock( &p_vout->subpicture_lock ); + vlc_mutex_unlock( &p_spu->subpicture_lock ); } /***************************************************************************** - * vout_RenderSubPictures: render a subpicture list + * spu_RenderSubpictures: render a subpicture list ***************************************************************************** * This function renders all sub picture units in the list. *****************************************************************************/ -void vout_RenderSubPictures( vout_thread_t *p_vout, picture_t *p_pic_dst, - picture_t *p_pic_src, subpicture_t *p_subpic ) +void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt, + picture_t *p_pic_dst, picture_t *p_pic_src, + subpicture_t *p_subpic, + int i_scale_width_orig, int i_scale_height_orig ) { - /* Load the blending module */ - if( !p_vout->p_blend && p_subpic && p_subpic->p_region ) - { - p_vout->p_blend = vlc_object_create( p_vout, sizeof(filter_t) ); - vlc_object_attach( p_vout->p_blend, p_vout ); - p_vout->p_blend->fmt_out.video.i_x_offset = - p_vout->p_blend->fmt_out.video.i_y_offset = 0; - p_vout->p_blend->fmt_out.video.i_aspect = - p_vout->render.i_aspect; - p_vout->p_blend->fmt_out.video.i_chroma = - p_vout->output.i_chroma; - - p_vout->p_blend->fmt_in.video.i_chroma = VLC_FOURCC('Y','U','V','P'); - - p_vout->p_blend->p_module = - module_Need( p_vout->p_blend, "video blending", 0, 0 ); - } + /* Get lock */ + vlc_mutex_lock( &p_spu->subpicture_lock ); - /* Load the text rendering module */ - if( !p_vout->p_text && p_subpic && p_subpic->p_region ) + /* Check i_status again to make sure spudec hasn't destroyed the subpic */ + while( p_subpic != NULL && p_subpic->i_status != FREE_SUBPICTURE ) { - p_vout->p_text = vlc_object_create( p_vout, sizeof(filter_t) ); - vlc_object_attach( p_vout->p_text, p_vout ); + subpicture_region_t *p_region = p_subpic->p_region; + int i_scale_width, i_scale_height; + int i_subpic_x = p_subpic->i_x; - p_vout->p_text->fmt_out.video.i_width = - p_vout->p_text->fmt_out.video.i_visible_width = - p_vout->output.i_width; - p_vout->p_text->fmt_out.video.i_height = - p_vout->p_text->fmt_out.video.i_visible_height = - p_vout->output.i_height; + /* Load the blending module */ + if( !p_spu->p_blend && p_region ) + { + p_spu->p_blend = vlc_object_create( p_spu, VLC_OBJECT_FILTER ); + vlc_object_attach( p_spu->p_blend, p_spu ); + p_spu->p_blend->fmt_out.video.i_x_offset = + p_spu->p_blend->fmt_out.video.i_y_offset = 0; + p_spu->p_blend->fmt_out.video.i_aspect = p_fmt->i_aspect; + p_spu->p_blend->fmt_out.video.i_chroma = p_fmt->i_chroma; + p_spu->p_blend->fmt_in.video.i_chroma = VLC_FOURCC('Y','U','V','P'); + + p_spu->p_blend->p_module = + module_Need( p_spu->p_blend, "video blending", 0, 0 ); + } - p_vout->p_text->pf_spu_buffer_new = spu_new_buffer; - p_vout->p_text->pf_spu_buffer_del = spu_del_buffer; + /* Load the text rendering module */ + if( !p_spu->p_text && p_region ) + { + p_spu->p_text = vlc_object_create( p_spu, VLC_OBJECT_FILTER ); + vlc_object_attach( p_spu->p_text, p_spu ); + + p_spu->p_text->fmt_out.video.i_width = + p_spu->p_text->fmt_out.video.i_visible_width = + p_fmt->i_width; + p_spu->p_text->fmt_out.video.i_height = + p_spu->p_text->fmt_out.video.i_visible_height = + p_fmt->i_height; + + p_spu->p_text->pf_sub_buffer_new = spu_new_buffer; + p_spu->p_text->pf_sub_buffer_del = spu_del_buffer; + p_spu->p_text->p_module = + module_Need( p_spu->p_text, "text renderer", 0, 0 ); + } + else if( p_region ) + { + p_spu->p_text->fmt_out.video.i_width = + p_spu->p_text->fmt_out.video.i_visible_width = + p_fmt->i_width; + p_spu->p_text->fmt_out.video.i_height = + p_spu->p_text->fmt_out.video.i_visible_height = + p_fmt->i_height; + } - p_vout->p_text->p_module = - module_Need( p_vout->p_text, "text renderer", 0, 0 ); - } + i_scale_width = i_scale_width_orig; + i_scale_height = i_scale_height_orig; - /* Get lock */ - vlc_mutex_lock( &p_vout->subpicture_lock ); + if( p_subpic->i_original_picture_width && + p_subpic->i_original_picture_height ) + { + i_scale_width = i_scale_width * p_fmt->i_width / + p_subpic->i_original_picture_width; + i_scale_height = i_scale_height * p_fmt->i_height / + p_subpic->i_original_picture_height; + } - /* Check i_status again to make sure spudec hasn't destroyed the subpic */ - while( p_subpic != NULL && p_subpic->i_status != FREE_SUBPICTURE ) - { - subpicture_region_t *p_region = p_subpic->p_region; + /* Set default subpicture aspect ratio */ + if( p_region && p_region->fmt.i_aspect && + (!p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den) ) + { + p_region->fmt.i_sar_den = p_region->fmt.i_aspect; + p_region->fmt.i_sar_num = VOUT_ASPECT_FACTOR; + } + if( p_region && + (!p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den) ) + { + p_region->fmt.i_sar_den = p_fmt->i_sar_den; + p_region->fmt.i_sar_num = p_fmt->i_sar_num; + } + + /* Take care of the aspect ratio */ + if( p_region && p_region->fmt.i_sar_num * p_fmt->i_sar_den != + p_region->fmt.i_sar_den * p_fmt->i_sar_num ) + { + i_scale_width = i_scale_width * + (int64_t)p_region->fmt.i_sar_num * p_fmt->i_sar_den / + p_region->fmt.i_sar_den / p_fmt->i_sar_num; + i_subpic_x = p_subpic->i_x * i_scale_width / 1000; + } - if( p_subpic->pf_render ) + /* Load the scaling module */ + if( !p_spu->p_scale && (i_scale_width != 1000 || + i_scale_height != 1000) ) { - p_subpic->pf_render( p_vout, p_pic_dst, p_subpic ); + p_spu->p_scale = vlc_object_create( p_spu, VLC_OBJECT_FILTER ); + vlc_object_attach( p_spu->p_scale, p_spu ); + p_spu->p_scale->fmt_out.video.i_chroma = + p_spu->p_scale->fmt_in.video.i_chroma = + VLC_FOURCC('Y','U','V','P'); + p_spu->p_scale->fmt_in.video.i_width = + p_spu->p_scale->fmt_in.video.i_height = 32; + p_spu->p_scale->fmt_out.video.i_width = + p_spu->p_scale->fmt_out.video.i_height = 16; + + p_spu->p_scale->pf_vout_buffer_new = spu_new_video_buffer; + p_spu->p_scale->pf_vout_buffer_del = spu_del_video_buffer; + p_spu->p_scale->p_module = + module_Need( p_spu->p_scale, "video filter2", 0, 0 ); } - else while( p_region && p_vout->p_blend && - p_vout->p_blend->pf_video_blend ) + + while( p_region && p_spu->p_blend && p_spu->p_blend->pf_video_blend ) { - int i_x_offset = p_region->i_x + p_subpic->i_x; + int i_fade_alpha = 255; + int i_x_offset = p_region->i_x + i_subpic_x; int i_y_offset = p_region->i_y + p_subpic->i_y; if( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') ) { - if( p_vout->p_text && p_vout->p_text->p_module && - p_vout->p_text->pf_render_string ) + if( p_spu->p_text && p_spu->p_text->p_module && + p_spu->p_text->pf_render_text ) { - /* TODO: do it in a less hacky way - * (modify text renderer API) */ - subpicture_t *p_spu; - subpicture_region_t tmp_region; - block_t *p_new_block = - block_New( p_vout, strlen(p_region->psz_text) + 1 ); - - if( p_new_block ) - { - memcpy( p_new_block->p_buffer, p_region->psz_text, - p_new_block->i_buffer ); - p_new_block->i_pts = p_new_block->i_dts = - p_subpic->i_start; - p_new_block->i_length = - p_subpic->i_start - p_subpic->i_stop; - p_spu = p_vout->p_text->pf_render_string( - p_vout->p_text, p_new_block ); - - if( p_spu ) - { - tmp_region = *p_region; - *p_region = *p_spu->p_region; - p_region->p_next = tmp_region.p_next; - *p_spu->p_region = tmp_region; - p_vout->p_text->pf_spu_buffer_del( p_vout->p_text, - p_spu ); - } - } + p_region->i_text_align = p_subpic->i_flags & 0x3; + p_spu->p_text->pf_render_text( p_spu->p_text, + p_region, p_region ); } } - if( p_subpic->i_flags & OSD_ALIGN_BOTTOM ) + /* Force palette if requested */ + if( p_spu->b_force_palette && VLC_FOURCC('Y','U','V','P') == + p_region->fmt.i_chroma ) { - i_y_offset = p_vout->output.i_height - p_region->fmt.i_height - + memcpy( p_region->fmt.p_palette->palette, + p_spu->palette, 16 ); + } + + /* Scale SPU if necessary */ + if( p_region->p_cache ) + { + if( i_scale_width * p_region->fmt.i_width / 1000 != + p_region->p_cache->fmt.i_width || + i_scale_height * p_region->fmt.i_height / 1000 != + p_region->p_cache->fmt.i_height ) + { + p_subpic->pf_destroy_region( VLC_OBJECT(p_spu), + p_region->p_cache ); + p_region->p_cache = 0; + } + } + + if( (i_scale_width != 1000 || i_scale_height != 1000) && + p_spu->p_scale && !p_region->p_cache ) + { + picture_t *p_pic; + + p_spu->p_scale->fmt_in.video = p_region->fmt; + p_spu->p_scale->fmt_out.video = p_region->fmt; + + p_region->p_cache = + p_subpic->pf_create_region( VLC_OBJECT(p_spu), + &p_spu->p_scale->fmt_out.video ); + if( p_spu->p_scale->fmt_out.video.p_palette ) + *p_spu->p_scale->fmt_out.video.p_palette = + *p_region->fmt.p_palette; + p_region->p_cache->p_next = p_region->p_next; + + vout_CopyPicture( p_spu, &p_region->p_cache->picture, + &p_region->picture ); + + p_spu->p_scale->fmt_out.video.i_width = + p_region->fmt.i_width * i_scale_width / 1000; + p_spu->p_scale->fmt_out.video.i_visible_width = + p_region->fmt.i_visible_width * i_scale_width / 1000; + p_spu->p_scale->fmt_out.video.i_height = + p_region->fmt.i_height * i_scale_height / 1000; + p_spu->p_scale->fmt_out.video.i_visible_height = + p_region->fmt.i_visible_height * i_scale_height / 1000; + p_region->p_cache->fmt = p_spu->p_scale->fmt_out.video; + p_region->p_cache->i_x = p_region->i_x * i_scale_width / 1000; + p_region->p_cache->i_y = p_region->i_y * i_scale_height / 1000; + + p_pic = p_spu->p_scale->pf_video_filter( + p_spu->p_scale, &p_region->p_cache->picture ); + if( p_pic ) + { + picture_t p_pic_tmp = p_region->p_cache->picture; + p_region->p_cache->picture = *p_pic; + *p_pic = p_pic_tmp; + free( p_pic ); + } + } + if( (i_scale_width != 1000 || i_scale_height != 1000) && + p_spu->p_scale && p_region->p_cache ) + { + p_region = p_region->p_cache; + } + + if( p_subpic->i_flags & SUBPICTURE_ALIGN_BOTTOM ) + { + i_y_offset = p_fmt->i_height - p_region->fmt.i_height - p_subpic->i_y; } - else if ( !(p_subpic->i_flags & OSD_ALIGN_TOP) ) + else if ( !(p_subpic->i_flags & SUBPICTURE_ALIGN_TOP) ) { - i_y_offset = p_vout->output.i_height / 2 - - p_region->fmt.i_height / 2; + i_y_offset = p_fmt->i_height / 2 - p_region->fmt.i_height / 2; } - if( p_subpic->i_flags & OSD_ALIGN_RIGHT ) + if( p_subpic->i_flags & SUBPICTURE_ALIGN_RIGHT ) { - i_x_offset = p_vout->output.i_width - p_region->fmt.i_width - - p_subpic->i_x; + i_x_offset = p_fmt->i_width - p_region->fmt.i_width - + i_subpic_x; } - else if ( !(p_subpic->i_flags & OSD_ALIGN_LEFT) ) + else if ( !(p_subpic->i_flags & SUBPICTURE_ALIGN_LEFT) ) { - i_x_offset = p_vout->output.i_width / 2 - - p_region->fmt.i_width / 2; + i_x_offset = p_fmt->i_width / 2 - p_region->fmt.i_width / 2; } if( p_subpic->b_absolute ) { - i_x_offset = p_region->i_x + p_subpic->i_x; - i_y_offset = p_region->i_y + p_subpic->i_y; + i_x_offset = p_region->i_x + + i_subpic_x * i_scale_width / 1000; + i_y_offset = p_region->i_y + + p_subpic->i_y * i_scale_height / 1000; + + } + + if( p_spu->i_margin != 0 && p_spu->b_force_crop == VLC_FALSE ) + { + int i_diff = 0; + int i_low = i_y_offset - p_spu->i_margin; + int i_high = i_y_offset + p_region->fmt.i_height - p_spu->i_margin; + + /* crop extra margin to keep within bounds */ + if( i_low < 0 ) i_diff = i_low; + if( i_high > (int)p_fmt->i_height ) i_diff = i_high - p_fmt->i_height; + i_y_offset -= ( p_spu->i_margin + i_diff ); } - p_vout->p_blend->fmt_in.video = p_region->fmt; + p_spu->p_blend->fmt_in.video = p_region->fmt; /* Force cropping if requested */ - if( p_vout->b_force_crop ) + if( p_spu->b_force_crop ) { - video_format_t *p_fmt = &p_vout->p_blend->fmt_in.video; + video_format_t *p_fmt = &p_spu->p_blend->fmt_in.video; + int i_crop_x = p_spu->i_crop_x * i_scale_width / 1000; + int i_crop_y = p_spu->i_crop_y * i_scale_height / 1000; + int i_crop_width = p_spu->i_crop_width * i_scale_width / 1000; + int i_crop_height = p_spu->i_crop_height * i_scale_height/1000; /* Find the intersection */ - if( p_vout->i_crop_x + p_vout->i_crop_width <= i_x_offset || - i_x_offset + (int)p_fmt->i_visible_width < - p_vout->i_crop_x || - p_vout->i_crop_y + p_vout->i_crop_height <= i_y_offset || - i_y_offset + (int)p_fmt->i_visible_height < - p_vout->i_crop_y ) + if( i_crop_x + i_crop_width <= i_x_offset || + i_x_offset + (int)p_fmt->i_visible_width < i_crop_x || + i_crop_y + i_crop_height <= i_y_offset || + i_y_offset + (int)p_fmt->i_visible_height < i_crop_y ) { /* No intersection */ p_fmt->i_visible_width = p_fmt->i_visible_height = 0; @@ -505,11 +731,11 @@ void vout_RenderSubPictures( vout_thread_t *p_vout, picture_t *p_pic_dst, else { int i_x, i_y, i_x_end, i_y_end; - i_x = __MAX( p_vout->i_crop_x, i_x_offset ); - i_y = __MAX( p_vout->i_crop_y, i_y_offset ); - i_x_end = __MIN( p_vout->i_crop_x + p_vout->i_crop_width, + i_x = __MAX( i_crop_x, i_x_offset ); + i_y = __MAX( i_crop_y, i_y_offset ); + i_x_end = __MIN( i_crop_x + i_crop_width, i_x_offset + (int)p_fmt->i_visible_width ); - i_y_end = __MIN( p_vout->i_crop_y + p_vout->i_crop_height, + i_y_end = __MIN( i_crop_y + i_crop_height, i_y_offset + (int)p_fmt->i_visible_height ); p_fmt->i_x_offset = i_x - i_x_offset; @@ -522,30 +748,29 @@ void vout_RenderSubPictures( vout_thread_t *p_vout, picture_t *p_pic_dst, } } - /* Force palette if requested */ - if( p_vout->b_force_alpha && VLC_FOURCC('Y','U','V','P') == - p_vout->p_blend->fmt_in.video.i_chroma ) + /* Update the output picture size */ + p_spu->p_blend->fmt_out.video.i_width = + p_spu->p_blend->fmt_out.video.i_visible_width = + p_fmt->i_width; + p_spu->p_blend->fmt_out.video.i_height = + p_spu->p_blend->fmt_out.video.i_visible_height = + p_fmt->i_height; + + if( p_subpic->b_fade ) { - p_vout->p_blend->fmt_in.video.p_palette->palette[0][3] = - p_vout->pi_alpha[0]; - p_vout->p_blend->fmt_in.video.p_palette->palette[1][3] = - p_vout->pi_alpha[1]; - p_vout->p_blend->fmt_in.video.p_palette->palette[2][3] = - p_vout->pi_alpha[2]; - p_vout->p_blend->fmt_in.video.p_palette->palette[3][3] = - p_vout->pi_alpha[3]; + mtime_t i_fade_start = ( p_subpic->i_stop + + p_subpic->i_start ) / 2; + mtime_t i_now = mdate(); + if( i_now >= i_fade_start && p_subpic->i_stop > i_fade_start ) + { + i_fade_alpha = 255 * ( p_subpic->i_stop - i_now ) / + ( p_subpic->i_stop - i_fade_start ); + } } - /* Update the output picture size */ - p_vout->p_blend->fmt_out.video.i_width = - p_vout->p_blend->fmt_out.video.i_visible_width = - p_vout->output.i_width; - p_vout->p_blend->fmt_out.video.i_height = - p_vout->p_blend->fmt_out.video.i_visible_height = - p_vout->output.i_height; - - p_vout->p_blend->pf_video_blend( p_vout->p_blend, p_pic_dst, - p_pic_src, &p_region->picture, i_x_offset, i_y_offset ); + p_spu->p_blend->pf_video_blend( p_spu->p_blend, p_pic_dst, + p_pic_src, &p_region->picture, i_x_offset, i_y_offset, + i_fade_alpha * p_subpic->i_alpha / 255 ); p_region = p_region->p_next; } @@ -553,11 +778,11 @@ void vout_RenderSubPictures( vout_thread_t *p_vout, picture_t *p_pic_dst, p_subpic = p_subpic->p_next; } - vlc_mutex_unlock( &p_vout->subpicture_lock ); + vlc_mutex_unlock( &p_spu->subpicture_lock ); } /***************************************************************************** - * vout_SortSubPictures: find the subpictures to display + * spu_SortSubpictures: find the subpictures to display ***************************************************************************** * This function parses all subpictures and decides which ones need to be * displayed. This operation does not need lock, since only READY_SUBPICTURE @@ -567,102 +792,90 @@ void vout_RenderSubPictures( vout_thread_t *p_vout, picture_t *p_pic_dst, * to be removed if a newer one is available), which makes it a lot * more difficult to guess if a subpicture has to be rendered or not. *****************************************************************************/ -subpicture_t *vout_SortSubPictures( vout_thread_t *p_vout, - mtime_t display_date ) +subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date ) { - int i_index; - subpicture_t *p_subpic = NULL; - subpicture_t *p_ephemer = NULL; - mtime_t ephemer_date = 0; + int i_index, i_channel; + subpicture_t *p_subpic = NULL; + subpicture_t *p_ephemer; + mtime_t ephemer_date; + + /* Run subpicture filters */ + for( i_index = 0; i_index < p_spu->i_filter; i_index++ ) + { + subpicture_t *p_subpic_filter; + p_subpic_filter = p_spu->pp_filter[i_index]-> + pf_sub_filter( p_spu->pp_filter[i_index], display_date ); + if( p_subpic_filter ) + { + spu_DisplaySubpicture( p_spu, p_subpic_filter ); + } + } /* We get an easily parsable chained list of subpictures which * ends with NULL since p_subpic was initialized to NULL. */ - for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ ) + for( i_channel = 0; i_channel < p_spu->i_channel; i_channel++ ) { - if( p_vout->p_subpicture[i_index].i_status == READY_SUBPICTURE ) + p_ephemer = 0; + ephemer_date = 0; + + for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ ) { - /* If it is a DVD subpicture, check its date */ - if( p_vout->p_subpicture[i_index].i_type == MEMORY_SUBPICTURE ) + if( p_spu->p_subpicture[i_index].i_channel != i_channel || + p_spu->p_subpicture[i_index].i_status != READY_SUBPICTURE ) { - if( !p_vout->p_subpicture[i_index].b_ephemer - && display_date > p_vout->p_subpicture[i_index].i_stop ) - { - /* Too late, destroy the subpic */ - vout_DestroySubPicture( p_vout, - &p_vout->p_subpicture[i_index] ); - continue; - } - - if( display_date - && display_date < p_vout->p_subpicture[i_index].i_start ) - { - /* Too early, come back next monday */ - continue; - } - - /* If this is an ephemer subpic, see if it's the - * youngest we have */ - if( p_vout->p_subpicture[i_index].b_ephemer ) - { - if( p_ephemer == NULL ) - { - p_ephemer = &p_vout->p_subpicture[i_index]; - continue; - } - - if( p_vout->p_subpicture[i_index].i_start - < p_ephemer->i_start ) - { - /* Link the previous ephemer subpicture and - * replace it with the current one */ - p_ephemer->p_next = p_subpic; - p_subpic = p_ephemer; - p_ephemer = &p_vout->p_subpicture[i_index]; - - /* If it's the 2nd youngest subpicture, - * register its date */ - if( !ephemer_date - || ephemer_date > p_subpic->i_start ) - { - ephemer_date = p_subpic->i_start; - } - - continue; - } - } + continue; + } + if( display_date && + display_date < p_spu->p_subpicture[i_index].i_start ) + { + /* Too early, come back next monday */ + continue; + } - p_vout->p_subpicture[i_index].p_next = p_subpic; - p_subpic = &p_vout->p_subpicture[i_index]; + if( p_spu->p_subpicture[i_index].i_start > ephemer_date ) + ephemer_date = p_spu->p_subpicture[i_index].i_start; - /* If it's the 2nd youngest subpicture, register its date */ - if( !ephemer_date || ephemer_date > p_subpic->i_start ) - { - ephemer_date = p_subpic->i_start; - } + if( display_date > p_spu->p_subpicture[i_index].i_stop && + ( !p_spu->p_subpicture[i_index].b_ephemer || + p_spu->p_subpicture[i_index].i_stop > + p_spu->p_subpicture[i_index].i_start ) ) + { + /* Too late, destroy the subpic */ + spu_DestroySubpicture( p_spu, &p_spu->p_subpicture[i_index] ); + continue; } - /* If it's not a DVD subpicture, just register it */ - else + + /* If this is an ephemer subpic, add it to our list */ + if( p_spu->p_subpicture[i_index].b_ephemer ) { - p_vout->p_subpicture[i_index].p_next = p_subpic; - p_subpic = &p_vout->p_subpicture[i_index]; + p_spu->p_subpicture[i_index].p_next = p_ephemer; + p_ephemer = &p_spu->p_subpicture[i_index]; + + continue; } - } - } - /* If we found an ephemer subpicture, check if it has to be - * displayed */ - if( p_ephemer != NULL ) - { - if( p_ephemer->i_start <= ephemer_date ) - { - /* Ephemer subpicture has lived too long */ - vout_DestroySubPicture( p_vout, p_ephemer ); + p_spu->p_subpicture[i_index].p_next = p_subpic; + p_subpic = &p_spu->p_subpicture[i_index]; } - else + + /* If we found ephemer subpictures, check if they have to be + * displayed or destroyed */ + while( p_ephemer != NULL ) { - /* Ephemer subpicture can still live a bit */ - p_ephemer->p_next = p_subpic; - return p_ephemer; + subpicture_t *p_tmp = p_ephemer; + p_ephemer = p_ephemer->p_next; + + if( p_tmp->i_start < ephemer_date ) + { + /* Ephemer subpicture has lived too long */ + spu_DestroySubpicture( p_spu, p_tmp ); + } + else + { + /* Ephemer subpicture can still live a bit */ + p_tmp->p_next = p_subpic; + p_subpic = p_tmp; + } } } @@ -670,43 +883,21 @@ subpicture_t *vout_SortSubPictures( vout_thread_t *p_vout, } /***************************************************************************** - * vout_RegisterOSDChannel: register an OSD channel - ***************************************************************************** - * This function affects an ID to an OSD channel - *****************************************************************************/ -int vout_RegisterOSDChannel( vout_thread_t *p_vout ) -{ - msg_Dbg( p_vout, "Registering OSD channel, ID: %i", - p_vout->i_channel_count + 1 ); - return ++p_vout->i_channel_count; -} - -/***************************************************************************** - * vout_ClearOSDChannel: clear an OSD channel + * SpuClearChannel: clear an spu channel ***************************************************************************** - * This function destroys the subpictures which belong to the OSD channel + * This function destroys the subpictures which belong to the spu channel * corresponding to i_channel_id. *****************************************************************************/ -void vout_ClearOSDChannel( vout_thread_t *p_vout, int i_channel ) +static void SpuClearChannel( spu_t *p_spu, int i_channel ) { - int i_subpic; /* subpicture index */ - subpicture_t * p_subpic = NULL; /* first free subpicture */ - - if( i_channel == DEFAULT_CHAN ) - { - if( p_vout->p_default_channel != NULL ) - { - vout_DestroySubPicture( p_vout, p_vout->p_default_channel ); - } - p_vout->p_default_channel = NULL; - return; - } + int i_subpic; /* subpicture index */ + subpicture_t *p_subpic = NULL; /* first free subpicture */ - vlc_mutex_lock( &p_vout->subpicture_lock ); + vlc_mutex_lock( &p_spu->subpicture_lock ); for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ ) { - p_subpic = &p_vout->p_subpicture[i_subpic]; + p_subpic = &p_spu->p_subpicture[i_subpic]; if( p_subpic->i_status == FREE_SUBPICTURE || ( p_subpic->i_status != RESERVED_SUBPICTURE && p_subpic->i_status != READY_SUBPICTURE ) ) @@ -720,72 +911,85 @@ void vout_ClearOSDChannel( vout_thread_t *p_vout, int i_channel ) { subpicture_region_t *p_region = p_subpic->p_region; p_subpic->p_region = p_region->p_next; - spu_DestroyRegion( p_vout, p_region ); + spu_DestroyRegion( p_spu, p_region ); } - if( p_subpic->pf_destroy ) - { - p_subpic->pf_destroy( p_subpic ); - } + if( p_subpic->pf_destroy ) p_subpic->pf_destroy( p_subpic ); p_subpic->i_status = FREE_SUBPICTURE; } } - vlc_mutex_unlock( &p_vout->subpicture_lock ); + vlc_mutex_unlock( &p_spu->subpicture_lock ); +} + +/***************************************************************************** + * spu_ControlDefault: default methods for the subpicture unit control. + *****************************************************************************/ +static int spu_vaControlDefault( spu_t *p_spu, int i_query, va_list args ) +{ + int *pi, i; + + switch( i_query ) + { + case SPU_CHANNEL_REGISTER: + pi = (int *)va_arg( args, int * ); + if( pi ) *pi = p_spu->i_channel++; + msg_Dbg( p_spu, "Registering subpicture channel, ID: %i", + p_spu->i_channel - 1 ); + break; + + case SPU_CHANNEL_CLEAR: + i = (int)va_arg( args, int ); + SpuClearChannel( p_spu, i ); + break; + + default: + msg_Dbg( p_spu, "control query not supported" ); + return VLC_EGENERIC; + } + + return VLC_SUCCESS; } +/***************************************************************************** + * Object variables callbacks + *****************************************************************************/ + /***************************************************************************** * UpdateSPU: update subpicture settings ***************************************************************************** * This function is called from CropCallback and at initialization time, to * retrieve crop information from the input. *****************************************************************************/ -static void UpdateSPU( vout_thread_t *p_vout, vlc_object_t *p_object ) +static void UpdateSPU( spu_t *p_spu, vlc_object_t *p_object ) { vlc_value_t val; - p_vout->b_force_alpha = VLC_FALSE; - p_vout->b_force_crop = VLC_FALSE; + p_spu->b_force_palette = VLC_FALSE; + p_spu->b_force_crop = VLC_FALSE; if( var_Get( p_object, "highlight", &val ) || !val.b_bool ) return; - p_vout->b_force_crop = VLC_TRUE; + p_spu->b_force_crop = VLC_TRUE; var_Get( p_object, "x-start", &val ); - p_vout->i_crop_x = val.i_int; + p_spu->i_crop_x = val.i_int; var_Get( p_object, "y-start", &val ); - p_vout->i_crop_y = val.i_int; + p_spu->i_crop_y = val.i_int; var_Get( p_object, "x-end", &val ); - p_vout->i_crop_width = val.i_int - p_vout->i_crop_x; + p_spu->i_crop_width = val.i_int - p_spu->i_crop_x; var_Get( p_object, "y-end", &val ); - p_vout->i_crop_height = val.i_int - p_vout->i_crop_y; - -#if 0 - if( var_Get( p_object, "color", &val ) == VLC_SUCCESS ) - { - int i; - for( i = 0; i < 4; i++ ) - { - p_vout->pi_color[i] = ((uint8_t *)val.p_address)[i]; - } - } -#endif + p_spu->i_crop_height = val.i_int - p_spu->i_crop_y; - if( var_Get( p_object, "contrast", &val ) == VLC_SUCCESS ) + if( var_Get( p_object, "menu-palette", &val ) == VLC_SUCCESS ) { - int i; - for( i = 0; i < 4; i++ ) - { - p_vout->pi_alpha[i] = ((uint8_t *)val.p_address)[i]; - p_vout->pi_alpha[i] = p_vout->pi_alpha[i] == 0xf ? - 0xff : p_vout->pi_alpha[i] << 4; - } - p_vout->b_force_alpha = VLC_TRUE; + memcpy( p_spu->palette, val.p_address, 16 ); + p_spu->b_force_palette = VLC_TRUE; } - msg_Dbg( p_vout, "crop: %i,%i,%i,%i, alpha: %i", - p_vout->i_crop_x, p_vout->i_crop_y, - p_vout->i_crop_width, p_vout->i_crop_height, - p_vout->b_force_alpha ); + msg_Dbg( p_object, "crop: %i,%i,%i,%i, palette forced: %i", + p_spu->i_crop_x, p_spu->i_crop_y, + p_spu->i_crop_width, p_spu->i_crop_height, + p_spu->b_force_palette ); } /***************************************************************************** @@ -796,13 +1000,27 @@ static void UpdateSPU( vout_thread_t *p_vout, vlc_object_t *p_object ) static int CropCallback( vlc_object_t *p_object, char const *psz_var, vlc_value_t oldval, vlc_value_t newval, void *p_data ) { - UpdateSPU( (vout_thread_t *)p_data, p_object ); + UpdateSPU( (spu_t *)p_data, p_object ); return VLC_SUCCESS; } /***************************************************************************** * Buffers allocation callbacks for the filters *****************************************************************************/ +static subpicture_t *sub_new_buffer( filter_t *p_filter ) +{ + filter_owner_sys_t *p_sys = p_filter->p_owner; + subpicture_t *p_subpicture = spu_CreateSubpicture( p_sys->p_spu ); + if( p_subpicture ) p_subpicture->i_channel = p_sys->i_channel; + return p_subpicture; +} + +static void sub_del_buffer( filter_t *p_filter, subpicture_t *p_subpic ) +{ + filter_owner_sys_t *p_sys = p_filter->p_owner; + spu_DestroySubpicture( p_sys->p_spu, p_subpic ); +} + static subpicture_t *spu_new_buffer( filter_t *p_filter ) { subpicture_t *p_subpic = (subpicture_t *)malloc(sizeof(subpicture_t)); @@ -810,6 +1028,7 @@ static subpicture_t *spu_new_buffer( filter_t *p_filter ) p_subpic->b_absolute = VLC_TRUE; p_subpic->pf_create_region = __spu_CreateRegion; + p_subpic->pf_make_region = __spu_MakeRegion; p_subpic->pf_destroy_region = __spu_DestroyRegion; return p_subpic; @@ -826,3 +1045,29 @@ static void spu_del_buffer( filter_t *p_filter, subpicture_t *p_subpic ) free( p_subpic ); } + +static picture_t *spu_new_video_buffer( filter_t *p_filter ) +{ + picture_t *p_picture = malloc( sizeof(picture_t) ); + + if( vout_AllocatePicture( p_filter, p_picture, + p_filter->fmt_out.video.i_chroma, + p_filter->fmt_out.video.i_width, + p_filter->fmt_out.video.i_height, + p_filter->fmt_out.video.i_aspect ) + != VLC_SUCCESS ) + { + free( p_picture ); + return NULL; + } + + p_picture->pf_release = RegionPictureRelease; + + return p_picture; +} + +static void spu_del_video_buffer( filter_t *p_filter, picture_t *p_pic ) +{ + if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig ); + if( p_pic ) free( p_pic ); +}