From 28ed0fc96153391a47fa4b480f716f0de1fbacae Mon Sep 17 00:00:00 2001 From: Gildas Bazin Date: Wed, 15 Sep 2004 15:50:54 +0000 Subject: [PATCH] * ALL: separation of the SPU engine from the VOUT. * modules/stream_out/transcode.c: re-use the SPU engine. * src/video_output/vout_subpictures.c: support for resizing subpictures. --- Makefile.am | 1 + include/video_output.h | 39 +- include/vlc/vout.h | 3 +- include/vlc_common.h | 6 +- include/vlc_filter.h | 4 +- include/vlc_objects.h | 2 + include/vlc_spu.h | 106 +++++ include/vlc_video.h | 2 +- modules/codec/cmml/intf.c | 19 +- modules/codec/ogt/common.c | 21 +- modules/codec/ogt/cvd.c | 4 +- modules/codec/ogt/cvd_parse.c | 14 +- modules/codec/ogt/ogt.c | 4 +- modules/codec/ogt/ogt_parse.c | 14 +- modules/control/hotkeys.c | 9 +- modules/stream_out/transcode.c | 252 ++--------- src/input/decoder.c | 24 +- src/misc/modules.c | 1 + src/misc/objects.c | 11 + src/video_output/video_output.c | 20 +- src/video_output/video_text.c | 6 +- src/video_output/video_widgets.c | 14 +- src/video_output/vout_pictures.c | 35 +- src/video_output/vout_subpictures.c | 659 +++++++++++++++++----------- 24 files changed, 643 insertions(+), 627 deletions(-) create mode 100644 include/vlc_spu.h diff --git a/Makefile.am b/Makefile.am index d13796c575..a64382bba7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -108,6 +108,7 @@ HEADERS_include = \ include/vlc_meta.h \ include/vlc_objects.h \ include/vlc_playlist.h \ + include/vlc_spu.h \ include/vlc_stream.h \ include/vlc_threads_funcs.h \ include/vlc_threads.h \ diff --git a/include/video_output.h b/include/video_output.h index 38c9568f24..2c23efff95 100644 --- a/include/video_output.h +++ b/include/video_output.h @@ -126,22 +126,8 @@ struct vout_thread_t /* Picture heap */ picture_t p_picture[2*VOUT_MAX_PICTURES+1]; /**< pictures */ - /* Subpicture properties */ - subpicture_t p_subpicture[VOUT_MAX_PICTURES]; /**< subpictures */ - subpicture_t *p_default_channel; /**< subpicture in the default - channel */ - int i_channel_count; /**< index of last subpicture - channel registered */ - - filter_t *p_blend; /**< alpha blending module */ - filter_t *p_text; /**< text renderer module */ - - vlc_bool_t b_force_crop; /**< force cropping of subpicture */ - int i_crop_x, i_crop_y, i_crop_width, i_crop_height; /**< cropping */ - - vlc_bool_t b_force_alpha; /**< force alpha palette of subpicture */ - uint8_t pi_alpha[4]; /**< forced alpha palette */ - + /* Subpicture unit */ + spu_t *p_spu; /* Statistics */ count_t c_loops; @@ -260,27 +246,6 @@ enum output_query_e VOUT_CLOSE }; -/** - * \addtogroup subpicture - * @{ - */ -VLC_EXPORT( subpicture_t *, vout_CreateSubPicture, ( vout_thread_t *, int, int ) ); -VLC_EXPORT( void, vout_DestroySubPicture, ( vout_thread_t *, subpicture_t * ) ); -VLC_EXPORT( void, vout_DisplaySubPicture, ( vout_thread_t *, subpicture_t * ) ); -VLC_EXPORT( int, vout_RegisterOSDChannel, ( vout_thread_t * ) ); -VLC_EXPORT( void, vout_ClearOSDChannel, ( vout_thread_t *, int ) ); -#define spu_CreateRegion(a,b) __spu_CreateRegion(VLC_OBJECT(a),b) -VLC_EXPORT( subpicture_region_t *,__spu_CreateRegion, ( vlc_object_t *, video_format_t * ) ); -#define spu_DestroyRegion(a,b) __spu_DestroyRegion(VLC_OBJECT(a),b) -VLC_EXPORT( void, __spu_DestroyRegion, ( vlc_object_t *, subpicture_region_t * ) ); - -void vout_InitSPU( vout_thread_t * ); -void vout_DestroySPU( vout_thread_t * ); -void vout_AttachSPU( vout_thread_t *, vlc_object_t *, vlc_bool_t ); -subpicture_t * vout_SortSubPictures ( vout_thread_t *, mtime_t ); -void vout_RenderSubPictures( vout_thread_t *, picture_t *, - picture_t *, subpicture_t * ); -/** @}*/ /** * @} */ diff --git a/include/vlc/vout.h b/include/vlc/vout.h index 2857e86c05..cebe310d62 100644 --- a/include/vlc/vout.h +++ b/include/vlc/vout.h @@ -2,7 +2,7 @@ * vout.h: video output header for vlc ***************************************************************************** * Copyright (C) 2002 VideoLAN - * $Id: vout.h,v 1.3 2004/01/25 18:17:08 zorglub Exp $ + * $Id$ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,6 +36,7 @@ extern "C" { *****************************************************************************/ #include "vlc_video.h" #include "video_output.h" +#include "vlc_spu.h" # ifdef __cplusplus } diff --git a/include/vlc_common.h b/include/vlc_common.h index 3781f0fb7c..11d5b8b1f2 100644 --- a/include/vlc_common.h +++ b/include/vlc_common.h @@ -279,16 +279,18 @@ typedef struct aout_filter_t aout_filter_t; /* Video */ typedef struct vout_thread_t vout_thread_t; typedef struct vout_sys_t vout_sys_t; +typedef struct vout_synchro_t vout_synchro_t; typedef struct chroma_sys_t chroma_sys_t; + typedef video_format_t video_frame_format_t; typedef struct picture_t picture_t; typedef struct picture_sys_t picture_sys_t; typedef struct picture_heap_t picture_heap_t; + +typedef struct spu_t spu_t; typedef struct subpicture_t subpicture_t; typedef struct subpicture_sys_t subpicture_sys_t; typedef struct subpicture_region_t subpicture_region_t; -typedef struct vout_synchro_t vout_synchro_t; -typedef struct text_renderer_sys_t text_renderer_sys_t; typedef struct text_style_t text_style_t; /* Stream output */ diff --git a/include/vlc_filter.h b/include/vlc_filter.h index 9bb4db92a2..f032946fd5 100644 --- a/include/vlc_filter.h +++ b/include/vlc_filter.h @@ -43,7 +43,7 @@ struct filter_t /* Module properties */ module_t * p_module; - filter_sys_t * p_sys; + filter_sys_t * p_sys; /* Input format */ es_format_t fmt_in; @@ -57,6 +57,8 @@ struct filter_t picture_t *, picture_t *, int, int ); + subpicture_t * ( *pf_subpicture_filter ) ( filter_t * ); + subpicture_t * ( *pf_render_string ) ( filter_t *, block_t * ); /* diff --git a/include/vlc_objects.h b/include/vlc_objects.h index 002fe10bad..70db7b6c78 100644 --- a/include/vlc_objects.h +++ b/include/vlc_objects.h @@ -54,6 +54,8 @@ #define VLC_OBJECT_STREAM (-20) #define VLC_OBJECT_OPENGL (-21) #define VLC_OBJECT_FILTER (-22) +#define VLC_OBJECT_VOD (-23) +#define VLC_OBJECT_SPU (-24) #define VLC_OBJECT_GENERIC (-666) diff --git a/include/vlc_spu.h b/include/vlc_spu.h new file mode 100644 index 0000000000..dfffd86f22 --- /dev/null +++ b/include/vlc_spu.h @@ -0,0 +1,106 @@ +/***************************************************************************** + * vlc_spu.h : subpicture unit + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id$ + * + * Authors: Gildas Bazin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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. + *****************************************************************************/ + +/** + * \defgroup spu Subpicture Unit + * This module describes the programming interface for the subpicture unit. + * It includes functions allowing to create/destroy an spu, create/destroy + * subpictures and render them. + * @{ + */ + +/** + * Subpicture unit descriptor + */ +struct spu_t +{ + VLC_COMMON_MEMBERS + + vlc_mutex_t subpicture_lock; /**< subpicture heap lock */ + subpicture_t p_subpicture[VOUT_MAX_PICTURES]; /**< subpictures */ + int i_channel; /**< number of subpicture channels registered */ + + filter_t *p_blend; /**< alpha blending module */ + filter_t *p_text; /**< text renderer module */ + filter_t *p_scale; /**< scaling module */ + + vlc_bool_t b_force_crop; /**< force cropping of subpicture */ + int i_crop_x, i_crop_y, i_crop_width, i_crop_height; /**< cropping */ + + int i_margin; /**< force position of a subpicture */ + vlc_bool_t b_force_alpha; /**< force alpha palette of subpicture */ + uint8_t pi_alpha[4]; /**< forced alpha palette */ + + int ( *pf_control ) ( spu_t *, int, va_list ); +}; + +static inline int spu_vaControl( spu_t *p_spu, int i_query, va_list args ) +{ + if( p_spu->pf_control ) + return p_spu->pf_control( p_spu, i_query, args ); + else + return VLC_EGENERIC; +} + +static inline int spu_Control( spu_t *p_spu, int i_query, ... ) +{ + va_list args; + int i_result; + + va_start( args, i_query ); + i_result = spu_vaControl( p_spu, i_query, args ); + va_end( args ); + return i_result; +} + +enum spu_query_e +{ + SPU_CHANNEL_REGISTER, /* arg1= int * res= */ + SPU_CHANNEL_CLEAR /* arg1= int res= */ +}; + +/** + * \addtogroup subpicture + * @{ + */ +#define spu_Init(a) __spu_Init(VLC_OBJECT(a)) +VLC_EXPORT( spu_t *, __spu_Init, ( vlc_object_t * ) ); +VLC_EXPORT( void, spu_Destroy, ( spu_t * ) ); +void spu_Attach( spu_t *, vlc_object_t *, vlc_bool_t ); + +VLC_EXPORT( subpicture_t *, spu_CreateSubpicture, ( spu_t * ) ); +VLC_EXPORT( void, spu_DestroySubpicture, ( spu_t *, subpicture_t * ) ); +VLC_EXPORT( void, spu_DisplaySubpicture, ( spu_t *, subpicture_t * ) ); + +#define spu_CreateRegion(a,b) __spu_CreateRegion(VLC_OBJECT(a),b) +VLC_EXPORT( subpicture_region_t *,__spu_CreateRegion, ( vlc_object_t *, video_format_t * ) ); +#define spu_DestroyRegion(a,b) __spu_DestroyRegion(VLC_OBJECT(a),b) +VLC_EXPORT( void, __spu_DestroyRegion, ( vlc_object_t *, subpicture_region_t * ) ); + +VLC_EXPORT( subpicture_t *, spu_SortSubpictures, ( spu_t *, mtime_t ) ); +VLC_EXPORT( void, spu_RenderSubpictures, ( spu_t *, video_format_t *, picture_t *, picture_t *, subpicture_t *, int, int ) ); + +/** @}*/ +/** + * @} + */ diff --git a/include/vlc_video.h b/include/vlc_video.h index dd962a02d7..2ecf6532e4 100644 --- a/include/vlc_video.h +++ b/include/vlc_video.h @@ -210,8 +210,8 @@ struct subpicture_region_t int i_y; /**< position of region */ subpicture_region_t *p_next; /**< next region in the list */ + subpicture_region_t *p_cache; /**< modified version of this region */ /**@}*/ - }; /** diff --git a/modules/codec/cmml/intf.c b/modules/codec/cmml/intf.c index a0a1d8a533..1222afb8a6 100644 --- a/modules/codec/cmml/intf.c +++ b/modules/codec/cmml/intf.c @@ -151,24 +151,11 @@ void E_(CloseIntf) ( vlc_object_t *p_this ) /* Erase the anchor text description from the video output if it exists */ p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE ); - if( p_vout != NULL && p_vout->p_subpicture != NULL ) + if( p_vout ) { - subpicture_t *p_subpic; - int i_subpic; - - for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ ) - { - p_subpic = &p_vout->p_subpicture[i_subpic]; - - if( p_subpic != NULL && - ( p_subpic->i_status == RESERVED_SUBPICTURE - || p_subpic->i_status == READY_SUBPICTURE ) ) - { - vout_DestroySubPicture( p_vout, p_subpic ); - } - } + spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR, DEFAULT_CHAN ); + vlc_object_release( p_vout ); } - if( p_vout ) vlc_object_release( p_vout ); var_DelCallback( p_intf->p_vlc, "key-pressed", KeyEvent, p_intf ); diff --git a/modules/codec/ogt/common.c b/modules/codec/ogt/common.c index 73e126bb8c..e12aebf53a 100644 --- a/modules/codec/ogt/common.c +++ b/modules/codec/ogt/common.c @@ -49,26 +49,11 @@ void VCDSubClose( vlc_object_t *p_this ) dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , ""); - if( !p_sys->b_packetizer ) + if( !p_sys->b_packetizer && p_sys->p_vout ) { /* FIXME check if it's ok to not lock vout */ - if( p_sys->p_vout != NULL && p_sys->p_vout->p_subpicture != NULL ) - { - subpicture_t * p_subpic; - int i_subpic; - - for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ ) - { - p_subpic = &p_sys->p_vout->p_subpicture[i_subpic]; - - if( p_subpic != NULL && - ( ( p_subpic->i_status == RESERVED_SUBPICTURE ) || - ( p_subpic->i_status == READY_SUBPICTURE ) ) ) - { - vout_DestroySubPicture( p_sys->p_vout, p_subpic ); - } - } - } + spu_Control( p_sys->p_vout->p_spu, SPU_CHANNEL_CLEAR, + p_sys->i_subpic_channel ); } if( p_sys->p_block ) diff --git a/modules/codec/ogt/cvd.c b/modules/codec/ogt/cvd.c index cccc8b8fa8..46abe55ca2 100644 --- a/modules/codec/ogt/cvd.c +++ b/modules/codec/ogt/cvd.c @@ -158,8 +158,8 @@ Decode ( decoder_t *p_dec, block_t **pp_block ) { if( p_last_vout != p_sys->p_vout ) { - p_sys->i_subpic_channel = - vout_RegisterOSDChannel( p_sys->p_vout ); + spu_Control( p_sys->p_vout->p_spu, SPU_CHANNEL_REGISTER, + &p_sys->i_subpic_channel ); } /* Parse and decode */ diff --git a/modules/codec/ogt/cvd_parse.c b/modules/codec/ogt/cvd_parse.c index a1916fa29b..289619729d 100644 --- a/modules/codec/ogt/cvd_parse.c +++ b/modules/codec/ogt/cvd_parse.c @@ -292,12 +292,10 @@ E_(ParsePacket)( decoder_t *p_dec) dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , ""); /* Allocate the subpicture internal data. */ - p_spu = vout_CreateSubPicture( p_sys->p_vout, p_sys->i_subpic_channel, - MEMORY_SUBPICTURE ); - if( p_spu == NULL ) - { - return; - } + p_spu = spu_CreateSubpicture( p_sys->p_vout->p_spu ); + if( p_spu == NULL ) return; + + p_spu->i_channel = p_sys->i_subpic_channel; /* In ParseImage we expand the run-length encoded color 0's; also we expand pixels and remove the color palette. This should @@ -349,12 +347,12 @@ E_(ParsePacket)( decoder_t *p_dec) if( ParseImage( p_dec, p_spu ) ) { /* There was a parse error, delete the subpicture */ - vout_DestroySubPicture( p_sys->p_vout, p_spu ); + spu_DestroySubpicture( p_sys->p_vout->p_spu, p_spu ); return; } /* SPU is finished - we can ask the video output to display it */ - vout_DisplaySubPicture( p_sys->p_vout, p_spu ); + spu_DisplaySubpicture( p_sys->p_vout->p_spu, p_spu ); } diff --git a/modules/codec/ogt/ogt.c b/modules/codec/ogt/ogt.c index 820d3232fc..54eca689c1 100644 --- a/modules/codec/ogt/ogt.c +++ b/modules/codec/ogt/ogt.c @@ -156,8 +156,8 @@ Decode ( decoder_t *p_dec, block_t **pp_block ) { if( p_last_vout != p_sys->p_vout ) { - p_sys->i_subpic_channel = - vout_RegisterOSDChannel( p_sys->p_vout ); + spu_Control( p_sys->p_vout->p_spu, SPU_CHANNEL_REGISTER, + &p_sys->i_subpic_channel ); } /* Parse and decode */ diff --git a/modules/codec/ogt/ogt_parse.c b/modules/codec/ogt/ogt_parse.c index b2b0b24874..a386ba30ff 100644 --- a/modules/codec/ogt/ogt_parse.c +++ b/modules/codec/ogt/ogt_parse.c @@ -165,12 +165,10 @@ E_(ParsePacket)( decoder_t *p_dec) dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , ""); /* Allocate the subpicture internal data. */ - p_spu = vout_CreateSubPicture( p_sys->p_vout, p_sys->i_subpic_channel, - MEMORY_SUBPICTURE ); - if( p_spu == NULL ) - { - return; - } + p_spu = spu_CreateSubpicture( p_sys->p_vout->p_spu ); + if( p_spu == NULL ) return; + + p_spu->i_channel = p_sys->i_subpic_channel; /* In ParseImage we expand the run-length encoded color 0's; also we expand pixels and remove the color palette. This should @@ -221,12 +219,12 @@ E_(ParsePacket)( decoder_t *p_dec) if( ParseImage( p_dec, p_spu ) ) { /* There was a parse error, delete the subpicture */ - vout_DestroySubPicture( p_sys->p_vout, p_spu ); + spu_DestroySubpicture( p_sys->p_vout->p_spu, p_spu ); return; } /* SPU is finished - we can ask the video output to display it */ - vout_DisplaySubPicture( p_sys->p_vout, p_spu ); + spu_DisplaySubpicture( p_sys->p_vout->p_spu, p_spu ); } diff --git a/modules/control/hotkeys.c b/modules/control/hotkeys.c index 78e8485537..6145792352 100755 --- a/modules/control/hotkeys.c +++ b/modules/control/hotkeys.c @@ -228,8 +228,8 @@ static void Run( intf_thread_t *p_intf ) { for( i = 0; i < CHANNELS_NUMBER; i++ ) { - p_intf->p_sys->p_channels[ i ] = - vout_RegisterOSDChannel( p_vout ); + spu_Control( p_vout->p_spu, SPU_CHANNEL_REGISTER, + &p_intf->p_sys->p_channels[ i ] ); } } @@ -734,10 +734,11 @@ static void ClearChannels( intf_thread_t *p_intf, vout_thread_t *p_vout ) if( p_vout ) { - vout_ClearOSDChannel( p_vout, DEFAULT_CHAN ); + spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR, DEFAULT_CHAN ); for( i = 0; i < CHANNELS_NUMBER; i++ ) { - vout_ClearOSDChannel( p_vout, p_intf->p_sys->p_channels[ i ] ); + spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR, + p_intf->p_sys->p_channels[ i ] ); } } } diff --git a/modules/stream_out/transcode.c b/modules/stream_out/transcode.c index c157faea70..bdaa17281f 100644 --- a/modules/stream_out/transcode.c +++ b/modules/stream_out/transcode.c @@ -222,8 +222,6 @@ static int transcode_spu_new ( sout_stream_t *, sout_stream_id_t * ); static void transcode_spu_close ( sout_stream_t *, sout_stream_id_t * ); static int transcode_spu_process( sout_stream_t *, sout_stream_id_t *, block_t *, block_t ** ); -static subpicture_t *transcode_spu_get( sout_stream_t *, sout_stream_id_t *, - mtime_t ); static int EncoderThread( struct sout_stream_sys_t * p_sys ); @@ -283,10 +281,7 @@ struct sout_stream_sys_t char *psz_senc; vlc_bool_t b_soverlay; sout_cfg_t *p_spu_cfg; - subpicture_t *pp_subpics[SUBPICTURE_RING_SIZE]; - - /* Filters */ - filter_t *p_filter_blend; + spu_t *p_spu; /* Sync */ vlc_bool_t b_audio_sync; @@ -310,7 +305,6 @@ static int Open( vlc_object_t *p_this ) sout_stream_t *p_stream = (sout_stream_t*)p_this; sout_stream_sys_t *p_sys; vlc_value_t val; - int i; p_sys = vlc_object_create( p_this, sizeof( sout_stream_sys_t ) ); @@ -458,9 +452,7 @@ static int Open( vlc_object_t *p_this ) var_Get( p_stream, SOUT_CFG_PREFIX "soverlay", &val ); p_sys->b_soverlay = val.b_bool; - p_sys->p_filter_blend = 0; - - for( i = 0; i < SUBPICTURE_RING_SIZE; i++ ) p_sys->pp_subpics[i] = 0; + p_sys->p_spu = 0; var_Get( p_stream, SOUT_CFG_PREFIX "audio-sync", &val ); p_sys->b_audio_sync = val.b_bool; @@ -481,7 +473,6 @@ static void Close( vlc_object_t * p_this ) { sout_stream_t *p_stream = (sout_stream_t*)p_this; sout_stream_sys_t *p_sys = p_stream->p_sys; - int i; sout_StreamDelete( p_sys->p_out ); @@ -527,24 +518,7 @@ static void Close( vlc_object_t * p_this ) } if( p_sys->psz_senc ) free( p_sys->psz_senc ); - if( p_sys->p_filter_blend ) - { - if( p_sys->p_filter_blend->p_module ) - module_Unneed( p_sys->p_filter_blend, - p_sys->p_filter_blend->p_module ); - - /* Clean-up pictures ring buffer */ - for( i = 0; i < PICTURE_RING_SIZE; i++ ) - { - if( p_sys->p_filter_blend->p_owner->pp_pics[i] ) - video_del_buffer( VLC_OBJECT(p_sys->p_filter_blend), - p_sys->p_filter_blend->p_owner->pp_pics[i] ); - } - free( p_sys->p_filter_blend->p_owner ); - - vlc_object_detach( p_sys->p_filter_blend ); - vlc_object_destroy( p_sys->p_filter_blend ); - } + if( p_sys->p_spu ) spu_Destroy( p_sys->p_spu ); vlc_object_destroy( p_sys ); } @@ -1553,104 +1527,42 @@ static int transcode_video_process( sout_stream_t *p_stream, */ /* Check if we have a subpicture to overlay */ - if( p_sys->p_filter_blend ) + if( p_sys->p_spu ) { - p_subpic = transcode_spu_get( p_stream, id, p_pic->date ); + p_subpic = spu_SortSubpictures( p_sys->p_spu, p_pic->date ); /* TODO: get another pic */ } /* Overlay subpicture */ if( p_subpic ) { - int i_width, i_height; + int i_scale_width, i_scale_height; + video_format_t *p_fmt; - p_sys->p_filter_blend->fmt_out = id->p_encoder->fmt_in; - p_sys->p_filter_blend->fmt_out.video.i_visible_width = - p_sys->p_filter_blend->fmt_out.video.i_width; - p_sys->p_filter_blend->fmt_out.video.i_visible_height = - p_sys->p_filter_blend->fmt_out.video.i_height; - p_sys->p_filter_blend->fmt_out.video.i_chroma = - VLC_FOURCC('I','4','2','0'); + i_scale_width = id->p_encoder->fmt_in.video.i_width * 1000 / + id->p_decoder->fmt_out.video.i_width; + i_scale_height = id->p_encoder->fmt_in.video.i_height * 1000 / + id->p_decoder->fmt_out.video.i_height; - i_width = id->p_encoder->fmt_in.video.i_width; - i_height = id->p_encoder->fmt_in.video.i_height; - - if( p_pic->i_refcount ) + if( p_pic->i_refcount && !id->i_filter ) { /* We can't modify the picture, we need to duplicate it */ - picture_t *p_tmp = - video_new_buffer_filter( p_sys->p_filter_blend ); + picture_t *p_tmp = video_new_buffer_decoder( id->p_decoder ); if( p_tmp ) { - int i, j; - for( i = 0; i < p_pic->i_planes; i++ ) - { - for( j = 0; j < p_pic->p[i].i_visible_lines; j++ ) - { - memcpy( p_tmp->p[i].p_pixels + j * - p_tmp->p[i].i_pitch, - p_pic->p[i].p_pixels + j * - p_pic->p[i].i_pitch, - p_tmp->p[i].i_visible_pitch ); - } - } - p_tmp->date = p_pic->date; - p_tmp->b_force = p_pic->b_force; - p_tmp->i_nb_fields = p_pic->i_nb_fields; - p_tmp->b_progressive = p_pic->b_progressive; - p_tmp->b_top_field_first = p_pic->b_top_field_first; + vout_CopyPicture( p_stream, p_tmp, p_pic ); p_pic->pf_release( p_pic ); p_pic = p_tmp; } } - while( p_subpic != NULL ) - { - subpicture_region_t *p_region = p_subpic->p_region; - - while( p_region && p_sys->p_filter_blend && - p_sys->p_filter_blend->pf_video_blend ) - { - int i_x_offset = p_region->i_x + p_subpic->i_x; - int i_y_offset = p_region->i_y + p_subpic->i_y; - - if( p_subpic->i_flags & OSD_ALIGN_BOTTOM ) - { - i_y_offset = i_height - p_region->fmt.i_height - - p_subpic->i_y; - } - else if ( !(p_subpic->i_flags & OSD_ALIGN_TOP) ) - { - i_y_offset = i_height / 2 - p_region->fmt.i_height / 2; - } - - if( p_subpic->i_flags & OSD_ALIGN_RIGHT ) - { - i_x_offset = i_width - p_region->fmt.i_width - - p_subpic->i_x; - } - else if ( !(p_subpic->i_flags & OSD_ALIGN_LEFT) ) - { - i_x_offset = 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; - } - - p_sys->p_filter_blend->fmt_in.video = p_region->fmt; - - p_sys->p_filter_blend->pf_video_blend( - p_sys->p_filter_blend, p_pic, p_pic, - &p_region->picture, i_x_offset, i_y_offset ); - - p_region = p_region->p_next; - } + if( id->i_filter ) + p_fmt = &id->pp_filter[id->i_filter -1]->fmt_out.video; + else + p_fmt = &id->p_decoder->fmt_out.video; - p_subpic = p_subpic->p_next; - } + spu_RenderSubpictures( p_sys->p_spu, p_fmt, p_pic, p_pic, p_subpic, + i_scale_width, i_scale_height ); } if( p_sys->i_threads >= 1 ) @@ -1872,6 +1784,7 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id ) /* Initialization of decoder structures */ id->p_decoder->pf_spu_buffer_new = spu_new_buffer; id->p_decoder->pf_spu_buffer_del = spu_del_buffer; + id->p_decoder->p_owner = (decoder_owner_sys_t *)p_stream; //id->p_decoder->p_cfg = p_sys->p_spu_cfg; id->p_decoder->p_module = @@ -1905,26 +1818,9 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id ) return VLC_EGENERIC; } } - else if( !p_sys->p_filter_blend ) + else if( !p_sys->p_spu ) { - int i; - - p_sys->p_filter_blend = - vlc_object_create( p_stream, VLC_OBJECT_FILTER ); - vlc_object_attach( p_sys->p_filter_blend, p_stream ); - p_sys->p_filter_blend->fmt_out.video.i_chroma = - VLC_FOURCC('I','4','2','0'); - p_sys->p_filter_blend->fmt_in.video.i_chroma = - VLC_FOURCC('Y','U','V','A'); - - p_sys->p_filter_blend->pf_vout_buffer_new = video_new_buffer_filter; - p_sys->p_filter_blend->pf_vout_buffer_del = video_del_buffer_filter; - p_sys->p_filter_blend->p_owner = malloc( sizeof(filter_owner_sys_t) ); - for( i = 0; i < PICTURE_RING_SIZE; i++ ) - p_sys->p_filter_blend->p_owner->pp_pics[i] = 0; - - p_sys->p_filter_blend->p_module = - module_Need( p_sys->p_filter_blend, "video blending", 0, 0 ); + p_sys->p_spu = spu_Init( p_stream ); } return VLC_SUCCESS; @@ -1932,9 +1828,6 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id ) static void transcode_spu_close( sout_stream_t *p_stream, sout_stream_id_t *id) { - sout_stream_sys_t *p_sys = p_stream->p_sys; - int i; - /* Close decoder */ if( id->p_decoder->p_module ) module_Unneed( id->p_decoder, id->p_decoder->p_module ); @@ -1942,15 +1835,6 @@ static void transcode_spu_close( sout_stream_t *p_stream, sout_stream_id_t *id) /* Close encoder */ if( id->p_encoder->p_module ) module_Unneed( id->p_encoder, id->p_encoder->p_module ); - - /* Free subpictures */ - for( i = 0; i < SUBPICTURE_RING_SIZE; i++ ) - { - if( !p_sys->pp_subpics[i] ) continue; - - spu_del_buffer( id->p_decoder, p_sys->pp_subpics[i] ); - p_sys->pp_subpics[i] = NULL; - } } static int transcode_spu_process( sout_stream_t *p_stream, @@ -1964,24 +1848,10 @@ static int transcode_spu_process( sout_stream_t *p_stream, p_subpic = id->p_decoder->pf_decode_sub( id->p_decoder, &in ); if( p_subpic && p_sys->b_soverlay ) { - int i; - - /* Find a free slot in our supictures ring buffer */ - for( i = 0; i < SUBPICTURE_RING_SIZE; i++ ) - { - if( !p_sys->pp_subpics[i] ) - { - p_sys->pp_subpics[i] = p_subpic; - break; - } - } - if( i == SUBPICTURE_RING_SIZE ) - { - spu_del_buffer( id->p_decoder, p_subpic ); - } + spu_DisplaySubpicture( p_sys->p_spu, p_subpic ); } - if( p_subpic && !p_sys->b_soverlay ) + if( p_subpic && !p_sys->b_soverlay ) { block_t *p_block; @@ -1998,78 +1868,14 @@ static int transcode_spu_process( sout_stream_t *p_stream, return VLC_EGENERIC; } -static subpicture_t *transcode_spu_get( sout_stream_t *p_stream, - sout_stream_id_t *id, - mtime_t display_date ) -{ - sout_stream_sys_t *p_sys = p_stream->p_sys; - subpicture_t *p_subpic = 0; - subpicture_t *p_ephemer = 0; - subpicture_t **pp_subpic = &p_subpic; - int i; - - /* Find current subpictures and remove old ones */ - for( i = 0; i < SUBPICTURE_RING_SIZE; i++ ) - { - if( !p_sys->pp_subpics[i] ) continue; - - if( !p_sys->pp_subpics[i]->b_ephemer && - p_sys->pp_subpics[i]->i_stop < display_date ) - { - spu_del_buffer( id->p_decoder, p_sys->pp_subpics[i] ); - p_sys->pp_subpics[i] = NULL; - continue; - } - - if( p_sys->pp_subpics[i]->i_start > display_date ) continue; - - if( p_sys->pp_subpics[i]->b_ephemer && !p_ephemer ) - { - p_ephemer = p_sys->pp_subpics[i]; - } - else if( p_sys->pp_subpics[i]->b_ephemer ) - { - if( p_ephemer->i_start < p_sys->pp_subpics[i]->i_start ) - { - subpicture_t tmp; - tmp = *p_ephemer; - *p_ephemer = *p_sys->pp_subpics[i]; - *p_sys->pp_subpics[i] = tmp; - } - - spu_del_buffer( id->p_decoder, p_sys->pp_subpics[i] ); - p_sys->pp_subpics[i] = NULL; - continue; - } - - /* Add subpicture to the list */ - *pp_subpic = p_sys->pp_subpics[i]; - pp_subpic = &p_sys->pp_subpics[i]->p_next; - } - - return p_subpic; -} - static subpicture_t *spu_new_buffer( decoder_t *p_dec ) { - subpicture_t *p_subpic = (subpicture_t *)malloc(sizeof(subpicture_t)); - memset( p_subpic, 0, sizeof(subpicture_t) ); - p_subpic->b_absolute = VLC_TRUE; - - p_subpic->pf_create_region = __spu_CreateRegion; - p_subpic->pf_destroy_region = __spu_DestroyRegion; - - return p_subpic; + sout_stream_t *p_stream = (sout_stream_t *)p_dec->p_owner; + return spu_CreateSubpicture( p_stream->p_sys->p_spu ); } static void spu_del_buffer( decoder_t *p_dec, subpicture_t *p_subpic ) { - while( p_subpic->p_region ) - { - subpicture_region_t *p_region = p_subpic->p_region; - p_subpic->p_region = p_region->p_next; - p_subpic->pf_destroy_region( VLC_OBJECT(p_dec), p_region ); - } - - free( p_subpic ); + sout_stream_t *p_stream = (sout_stream_t *)p_dec->p_owner; + spu_DestroySubpicture( p_stream->p_sys->p_spu, p_subpic ); } diff --git a/src/input/decoder.c b/src/input/decoder.c index 0cd2a9330e..e7cdabefc3 100644 --- a/src/input/decoder.c +++ b/src/input/decoder.c @@ -193,6 +193,9 @@ void input_DecoderDelete( decoder_t *p_dec ) } else { + /* Flush */ + input_DecoderDecode( p_dec, NULL ); + module_Unneed( p_dec, p_dec->p_module ); } @@ -667,7 +670,7 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE ); if( p_vout ) { - vout_DisplaySubPicture( p_vout, p_spu ); + spu_DisplaySubpicture( p_vout->p_spu, p_spu ); vlc_object_release( p_vout ); } } @@ -734,7 +737,8 @@ static void DeleteDecoder( decoder_t * p_dec ) p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE ); if( p_vout ) { - vout_ClearOSDChannel( p_vout, p_dec->p_owner->i_spu_channel ); + spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR, + p_dec->p_owner->i_spu_channel ); vlc_object_release( p_vout ); } } @@ -916,7 +920,7 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec ) { decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner; vout_thread_t *p_vout = NULL; - subpicture_t *p_spu; + subpicture_t *p_subpic; int i_attempts = 30; while( i_attempts-- ) @@ -937,20 +941,20 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec ) if( p_sys->p_spu_vout != p_vout ) { - p_sys->i_spu_channel = - vout_RegisterOSDChannel( p_vout ); + spu_Control( p_vout->p_spu, SPU_CHANNEL_REGISTER, + &p_sys->i_spu_channel ); p_sys->p_spu_vout = p_vout; } - p_spu = vout_CreateSubPicture( p_vout, p_sys->i_spu_channel, - MEMORY_SUBPICTURE ); + p_subpic = spu_CreateSubpicture( p_vout->p_spu ); + p_subpic->i_channel = p_sys->i_spu_channel; vlc_object_release( p_vout ); - return p_spu; + return p_subpic; } -static void spu_del_buffer( decoder_t *p_dec, subpicture_t *p_spu ) +static void spu_del_buffer( decoder_t *p_dec, subpicture_t *p_subpic ) { - vout_DestroySubPicture( p_dec->p_owner->p_vout, p_spu ); + spu_DestroySubpicture( p_dec->p_owner->p_vout->p_spu, p_subpic ); } diff --git a/src/misc/modules.c b/src/misc/modules.c index 06d78d0675..2225e2a5a4 100644 --- a/src/misc/modules.c +++ b/src/misc/modules.c @@ -91,6 +91,7 @@ #include "vlc_video.h" #include "video_output.h" #include "vout_synchro.h" +#include "vlc_spu.h" #include "audio_output.h" #include "aout_internal.h" diff --git a/src/misc/objects.c b/src/misc/objects.c index 7b953a13ba..4468182f32 100644 --- a/src/misc/objects.c +++ b/src/misc/objects.c @@ -39,6 +39,7 @@ #include "vlc_video.h" #include "video_output.h" +#include "vlc_spu.h" #include "audio_output.h" #include "aout_internal.h" @@ -51,6 +52,8 @@ #include "vlc_httpd.h" #include "vlc_vlm.h" +#include "vlc_vod.h" + /***************************************************************************** * Local prototypes *****************************************************************************/ @@ -158,6 +161,10 @@ void * __vlc_object_create( vlc_object_t *p_this, int i_type ) i_size = sizeof(vout_thread_t); psz_type = "video output"; break; + case VLC_OBJECT_SPU: + i_size = sizeof(spu_t); + psz_type = "subpicture unit"; + break; case VLC_OBJECT_AOUT: i_size = sizeof(aout_instance_t); psz_type = "audio output"; @@ -174,6 +181,10 @@ void * __vlc_object_create( vlc_object_t *p_this, int i_type ) i_size = sizeof( vlm_t ); psz_type = "vlm dameon"; break; + case VLC_OBJECT_VOD: + i_size = sizeof( vod_t ); + psz_type = "vod server"; + break; case VLC_OBJECT_OPENGL: i_size = sizeof( vout_thread_t ); psz_type = "opengl provider"; diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index 61201da03a..a4a1736e52 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -37,6 +37,7 @@ #include "vlc_video.h" #include "video_output.h" +#include "vlc_spu.h" #include /* for input_thread_t and i_pts_delay */ #if defined( SYS_DARWIN ) @@ -85,7 +86,7 @@ vout_thread_t * __vout_Request ( vlc_object_t *p_this, vout_thread_t *p_vout, if( p_playlist ) { - vout_AttachSPU( p_vout, p_this, VLC_FALSE ); + spu_Attach( p_vout->p_spu, p_this, VLC_FALSE ); vlc_object_detach( p_vout ); vlc_object_attach( p_vout, p_playlist ); @@ -180,7 +181,7 @@ vout_thread_t * __vout_Request ( vlc_object_t *p_this, vout_thread_t *p_vout, { /* This video output is cool! Hijack it. */ vlc_object_detach( p_vout ); - vout_AttachSPU( p_vout, p_this, VLC_TRUE ); + spu_Attach( p_vout->p_spu, p_this, VLC_TRUE ); vlc_object_attach( p_vout, p_this ); vlc_object_release( p_vout ); } @@ -234,10 +235,6 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, /* No images in the heap */ p_vout->i_heap_size = 0; - /* Register the default subpicture channel */ - p_vout->p_default_channel = NULL; - p_vout->i_channel_count = 1; - /* Initialize the rendering heap */ I_RENDERPICTURES = 0; p_vout->render.i_width = i_width; @@ -280,7 +277,6 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, /* Initialize locks */ vlc_mutex_init( p_vout, &p_vout->picture_lock ); - vlc_mutex_init( p_vout, &p_vout->subpicture_lock ); vlc_mutex_init( p_vout, &p_vout->change_lock ); /* Mouse coordinates */ @@ -291,8 +287,8 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER ); /* Initialize subpicture unit */ - vout_InitSPU( p_vout ); - vout_AttachSPU( p_vout, p_parent, VLC_TRUE ); + p_vout->p_spu = spu_Init( p_vout ); + spu_Attach( p_vout->p_spu, p_parent, VLC_TRUE ); /* Attach the new object now so we can use var inheritance below */ vlc_object_attach( p_vout, p_parent ); @@ -886,7 +882,7 @@ static void RunThread( vout_thread_t *p_vout) /* * Check for subpictures to display */ - p_subpic = vout_SortSubPictures( p_vout, display_date ); + p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date ); /* * Perform rendering @@ -1100,7 +1096,8 @@ static void EndThread( vout_thread_t *p_vout ) } /* Destroy subpicture unit */ - vout_DestroySPU( p_vout ); + spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), VLC_FALSE ); + spu_Destroy( p_vout->p_spu ); /* Destroy translation tables */ p_vout->pf_end( p_vout ); @@ -1119,7 +1116,6 @@ static void DestroyThread( vout_thread_t *p_vout ) { /* Destroy the locks */ vlc_mutex_destroy( &p_vout->picture_lock ); - vlc_mutex_destroy( &p_vout->subpicture_lock ); vlc_mutex_destroy( &p_vout->change_lock ); /* Release the module */ diff --git a/src/video_output/video_text.c b/src/video_output/video_text.c index 76b5677e85..27ab85afec 100644 --- a/src/video_output/video_text.c +++ b/src/video_output/video_text.c @@ -72,7 +72,7 @@ int vout_ShowTextAbsolute( vout_thread_t *p_vout, int i_channel, if( !psz_string ) return VLC_EGENERIC; - p_spu = vout_CreateSubPicture( p_vout, !DEFAULT_CHAN, MEMORY_SUBPICTURE ); + p_spu = spu_CreateSubpicture( p_vout->p_spu ); if( !p_spu ) return VLC_EGENERIC; /* Create a new subpicture region */ @@ -85,7 +85,7 @@ int vout_ShowTextAbsolute( vout_thread_t *p_vout, int i_channel, if( !p_spu->p_region ) { msg_Err( p_vout, "cannot allocate SPU region" ); - vout_DestroySubPicture( p_vout, p_spu ); + spu_DestroySubpicture( p_vout->p_spu, p_spu ); return VLC_EGENERIC; } @@ -100,7 +100,7 @@ int vout_ShowTextAbsolute( vout_thread_t *p_vout, int i_channel, p_spu->i_flags = i_flags; p_spu->i_channel = i_channel; - vout_DisplaySubPicture( p_vout, p_spu ); + spu_DisplaySubpicture( p_vout->p_spu, p_spu ); return VLC_SUCCESS; } diff --git a/src/video_output/video_widgets.c b/src/video_output/video_widgets.c index fd368de693..b3e4f7fb68 100644 --- a/src/video_output/video_widgets.c +++ b/src/video_output/video_widgets.c @@ -382,11 +382,12 @@ subpicture_t *vout_CreateWidget( vout_thread_t *p_vout, int i_channel ) p_widget = 0; /* Create and initialize a subpicture */ - p_subpic = vout_CreateSubPicture( p_vout, i_channel, MEMORY_SUBPICTURE ); + p_subpic = spu_CreateSubpicture( p_vout->p_spu ); if( p_subpic == NULL ) { return NULL; } + p_subpic->i_channel = i_channel; p_subpic->pf_render = Render; p_subpic->pf_destroy = FreeWidget; p_subpic->i_start = i_now; @@ -397,7 +398,7 @@ subpicture_t *vout_CreateWidget( vout_thread_t *p_vout, int i_channel ) if( p_widget == NULL ) { FreeWidget( p_subpic ); - vout_DestroySubPicture( p_vout, p_subpic ); + spu_DestroySubpicture( p_vout->p_spu, p_subpic ); return NULL; } p_subpic->p_sys = p_widget; @@ -454,7 +455,7 @@ void vout_OSDSlider( vlc_object_t *p_caller, int i_channel, int i_position, if( p_widget->p_pic == NULL ) { FreeWidget( p_subpic ); - vout_DestroySubPicture( p_vout, p_subpic ); + spu_DestroySubpicture( p_vout->p_spu, p_subpic ); return; } memset( p_widget->p_pic, 0, p_widget->i_width * p_widget->i_height ); @@ -462,7 +463,6 @@ void vout_OSDSlider( vlc_object_t *p_caller, int i_channel, int i_position, if( i_type == OSD_HOR_SLIDER ) { int i_x_pos = ( p_widget->i_width - 2 ) * i_position / 100; - int i_y_pos = p_widget->i_height / 2; DrawRect( p_vout, p_subpic, i_x_pos - 1, 2, i_x_pos + 1, p_widget->i_height - 3, STYLE_FILLED ); DrawRect( p_vout, p_subpic, 0, 0, p_widget->i_width - 1, @@ -482,7 +482,7 @@ void vout_OSDSlider( vlc_object_t *p_caller, int i_channel, int i_position, p_widget->i_height - 1, STYLE_EMPTY ); } - vout_DisplaySubPicture( p_vout, p_subpic ); + spu_DisplaySubpicture( p_vout->p_spu, p_subpic ); vlc_object_release( p_vout ); return; @@ -525,7 +525,7 @@ void vout_OSDIcon( vlc_object_t *p_caller, int i_channel, short i_type ) if( p_widget->p_pic == NULL ) { FreeWidget( p_subpic ); - vout_DestroySubPicture( p_vout, p_subpic ); + spu_DestroySubpicture( p_vout->p_spu, p_subpic ); return; } memset( p_widget->p_pic, 0, p_widget->i_width * p_widget->i_height ); @@ -567,7 +567,7 @@ void vout_OSDIcon( vlc_object_t *p_caller, int i_channel, short i_type ) } } - vout_DisplaySubPicture( p_vout, p_subpic ); + spu_DisplaySubpicture( p_vout->p_spu, p_subpic ); vlc_object_release( p_vout ); return; diff --git a/src/video_output/vout_pictures.c b/src/video_output/vout_pictures.c index b7fdaf6ead..f659cd758e 100644 --- a/src/video_output/vout_pictures.c +++ b/src/video_output/vout_pictures.c @@ -33,6 +33,7 @@ #include "vlc_video.h" #include "video_output.h" +#include "vlc_spu.h" #include "vout_pictures.h" @@ -285,6 +286,9 @@ void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic ) picture_t * vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, subpicture_t *p_subpic ) { + video_format_t fmt; + int i_scale_width, i_scale_height; + if( p_pic == NULL ) { /* XXX: subtitles */ @@ -292,6 +296,13 @@ picture_t * vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, return NULL; } + fmt.i_aspect = p_vout->output.i_aspect; + fmt.i_chroma = p_vout->output.i_chroma; + fmt.i_width = p_vout->output.i_width; + fmt.i_height = p_vout->output.i_height; + i_scale_width = p_vout->output.i_width * 1000 / p_vout->render.i_width; + i_scale_height = p_vout->output.i_height * 1000 / p_vout->render.i_height; + if( p_pic->i_type == DIRECT_PICTURE ) { if( !p_vout->render.b_allow_modify_pics || p_pic->i_refcount || @@ -307,8 +318,9 @@ picture_t * vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, * subtitles. */ vout_CopyPicture( p_vout, PP_OUTPUTPICTURE[0], p_pic ); - vout_RenderSubPictures( p_vout, PP_OUTPUTPICTURE[0], - p_pic , p_subpic ); + spu_RenderSubpictures( p_vout->p_spu, &fmt, + PP_OUTPUTPICTURE[0], p_pic, p_subpic, + i_scale_width, i_scale_height ); return PP_OUTPUTPICTURE[0]; } @@ -322,7 +334,8 @@ picture_t * vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, /* Picture is in a direct buffer but isn't used by the * decoder. We can safely render subtitles on it and * display it. */ - vout_RenderSubPictures( p_vout, p_pic, p_pic, p_subpic ); + spu_RenderSubpictures( p_vout->p_spu, &fmt, p_pic, p_pic, p_subpic, + i_scale_width, i_scale_height ); return p_pic; } @@ -340,7 +353,8 @@ picture_t * vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, return NULL; vout_CopyPicture( p_vout, PP_OUTPUTPICTURE[0], p_pic ); - vout_RenderSubPictures( p_vout, PP_OUTPUTPICTURE[0], p_pic, p_subpic ); + spu_RenderSubpictures( p_vout->p_spu, &fmt, PP_OUTPUTPICTURE[0], + p_pic, p_subpic, i_scale_width, i_scale_height); if( PP_OUTPUTPICTURE[0]->pf_unlock ) PP_OUTPUTPICTURE[0]->pf_unlock( p_vout, PP_OUTPUTPICTURE[0] ); @@ -374,7 +388,9 @@ picture_t * vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, p_vout->chroma.pf_convert( p_vout, p_pic, p_tmp_pic ); /* Render subpictures on the first direct buffer */ - vout_RenderSubPictures( p_vout, p_tmp_pic, p_tmp_pic, p_subpic ); + spu_RenderSubpictures( p_vout->p_spu, &fmt, p_tmp_pic, + p_tmp_pic, p_subpic, + i_scale_width, i_scale_height ); if( p_vout->p_picture[0].pf_lock ) if( p_vout->p_picture[0].pf_lock( p_vout, &p_vout->p_picture[0] ) ) @@ -392,8 +408,9 @@ picture_t * vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, p_vout->chroma.pf_convert( p_vout, p_pic, &p_vout->p_picture[0] ); /* Render subpictures on the first direct buffer */ - vout_RenderSubPictures( p_vout, &p_vout->p_picture[0], - &p_vout->p_picture[0], p_subpic ); + spu_RenderSubpictures( p_vout->p_spu, &fmt, &p_vout->p_picture[0], + &p_vout->p_picture[0], p_subpic, + i_scale_width, i_scale_height ); } if( p_vout->p_picture[0].pf_unlock ) @@ -929,4 +946,8 @@ void __vout_CopyPicture( vlc_object_t *p_this, } p_dest->date = p_src->date; + p_dest->b_force = p_src->b_force; + p_dest->i_nb_fields = p_src->i_nb_fields; + p_dest->b_progressive = p_src->b_progressive; + p_dest->b_top_field_first = p_src->b_top_field_first; } diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c index f9581e8726..725e0823e3 100644 --- a/src/video_output/vout_subpictures.c +++ b/src/video_output/vout_subpictures.c @@ -35,88 +35,113 @@ #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 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 * ); /** - * Initialise the subpicture decoder unit + * Initialise 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_Init( 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_spu->p_subpicture[i_index].i_type = EMPTY_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; + + /* Register the default subpicture channel */ + p_spu->i_channel = 1; + + vlc_mutex_init( p_this, &p_spu->subpicture_lock ); - 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; + vlc_object_attach( p_spu, p_this ); + + /* If the user requested an SPU margin, we force the position. */ + p_spu->i_margin = config_GetInt( p_spu, "spumargin" ); + + return p_spu; } /** - * 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_vout->p_text ); - vlc_object_destroy( p_vout->p_text ); + vlc_object_detach( p_spu->p_text ); + vlc_object_destroy( p_spu->p_text ); } - vout_AttachSPU( p_vout, VLC_OBJECT(p_vout), VLC_FALSE ); + 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_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_object_t *p_this, - 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; @@ -125,17 +150,16 @@ void vout_AttachSPU( vout_thread_t *p_vout, vlc_object_t *p_this, 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 ); } - } /** @@ -144,12 +168,17 @@ void vout_AttachSPU( vout_thread_t *p_vout, vlc_object_t *p_this, * \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; @@ -172,6 +201,8 @@ subpicture_region_t *__spu_CreateRegion( vlc_object_t *p_this, return NULL; } + p_region->picture.pf_release = RegionPictureRelease; + return p_region; } @@ -184,75 +215,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 @@ -260,11 +275,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; } } @@ -272,37 +287,21 @@ 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; - } + memset( p_subpic, 0, sizeof(subpicture_t) ); + p_subpic->i_type = MEMORY_SUBPICTURE; + p_subpic->i_status = RESERVED_SUBPICTURE; + p_subpic->b_absolute = VLC_TRUE; + p_subpic->pf_render = 0; + p_subpic->pf_destroy = 0; + p_subpic->p_sys = 0; - vlc_mutex_unlock( &p_vout->subpicture_lock ); + vlc_mutex_unlock( &p_spu->subpicture_lock ); p_subpic->pf_create_region = __spu_CreateRegion; p_subpic->pf_destroy_region = __spu_DestroyRegion; @@ -316,17 +315,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; } @@ -334,7 +333,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 ); } @@ -342,7 +341,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 ) @@ -352,19 +351,21 @@ 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, int i_scale_height ) { /* Get lock */ - vlc_mutex_lock( &p_vout->subpicture_lock ); + vlc_mutex_lock( &p_spu->subpicture_lock ); /* Check i_status again to make sure spudec hasn't destroyed the subpic */ while( p_subpic != NULL && p_subpic->i_status != FREE_SUBPICTURE ) @@ -372,64 +373,88 @@ void vout_RenderSubPictures( vout_thread_t *p_vout, picture_t *p_pic_dst, subpicture_region_t *p_region = p_subpic->p_region; /* Load the blending module */ - if( !p_vout->p_blend && p_region ) + if( !p_spu->p_blend && 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 ); + p_spu->p_blend = vlc_object_create( p_spu, sizeof(filter_t) ); + 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 ); } - + /* Load the text rendering module */ - if( !p_vout->p_text && p_region ) + if( !p_spu->p_text && p_region ) { - p_vout->p_text = vlc_object_create( p_vout, sizeof(filter_t) ); - vlc_object_attach( p_vout->p_text, p_vout ); - - 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; - - p_vout->p_text->pf_spu_buffer_new = spu_new_buffer; - p_vout->p_text->pf_spu_buffer_del = spu_del_buffer; - - p_vout->p_text->p_module = - module_Need( p_vout->p_text, "text renderer", 0, 0 ); + p_spu->p_text = vlc_object_create( p_spu, sizeof(filter_t) ); + 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_spu_buffer_new = spu_new_buffer; + p_spu->p_text->pf_spu_buffer_del = spu_del_buffer; + + p_spu->p_text->p_module = + module_Need( p_spu->p_text, "text renderer", 0, 0 ); + } + + /* Load the scaling module */ + if( !p_spu->p_scale && (i_scale_width != 1000 || + i_scale_height != 1000) ) + { + 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 ); } if( p_subpic->pf_render ) { - p_subpic->pf_render( p_vout, p_pic_dst, p_subpic ); + /* HACK to remove when the ogt subpic decoder is gone */ + if( p_spu->p_parent && + p_spu->p_parent->i_object_type == VLC_OBJECT_VOUT ) + { + vout_thread_t *p_vout = (vout_thread_t *)p_spu->p_parent; + p_subpic->pf_render( p_vout, p_pic_dst, p_subpic ); + } } - else while( p_region && p_vout->p_blend && - p_vout->p_blend->pf_video_blend ) + else 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_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_string ) { /* TODO: do it in a less hacky way * (modify text renderer API) */ - subpicture_t *p_spu; + subpicture_t *p_subpic_tmp; subpicture_region_t tmp_region; block_t *p_new_block = - block_New( p_vout, strlen(p_region->psz_text) + 1 ); + block_New( p_spu, strlen(p_region->psz_text) + 1 ); if( p_new_block ) { @@ -439,17 +464,17 @@ void vout_RenderSubPictures( vout_thread_t *p_vout, picture_t *p_pic_dst, 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 ); + p_subpic_tmp = p_spu->p_text->pf_render_string( + p_spu->p_text, p_new_block ); - if( p_spu ) + if( p_subpic_tmp ) { tmp_region = *p_region; - *p_region = *p_spu->p_region; + *p_region = *p_subpic_tmp->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_subpic_tmp->p_region = tmp_region; + p_spu->p_text->pf_spu_buffer_del( p_spu->p_text, + p_subpic_tmp ); } } } @@ -457,46 +482,52 @@ void vout_RenderSubPictures( vout_thread_t *p_vout, picture_t *p_pic_dst, if( p_subpic->i_flags & OSD_ALIGN_BOTTOM ) { - i_y_offset = p_vout->output.i_height - p_region->fmt.i_height - + 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) ) { - 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 ) { - i_x_offset = p_vout->output.i_width - p_region->fmt.i_width - + i_x_offset = p_fmt->i_width - p_region->fmt.i_width - p_subpic->i_x; } else if ( !(p_subpic->i_flags & OSD_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; - } - p_vout->p_blend->fmt_in.video = p_region->fmt; + if( p_spu->i_margin >= 0 ) + { + if( p_subpic->i_height + (unsigned int)p_spu->i_margin <= + p_fmt->i_height ) + { + i_y_offset = p_fmt->i_height - + p_spu->i_margin - p_subpic->i_height; + } + } + } /* 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; /* Find the intersection */ - if( p_vout->i_crop_x + p_vout->i_crop_width <= i_x_offset || + if( p_spu->i_crop_x + p_spu->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 || + p_spu->i_crop_x || + p_spu->i_crop_y + p_spu->i_crop_height <= i_y_offset || i_y_offset + (int)p_fmt->i_visible_height < - p_vout->i_crop_y ) + p_spu->i_crop_y ) { /* No intersection */ p_fmt->i_visible_width = p_fmt->i_visible_height = 0; @@ -504,11 +535,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( p_spu->i_crop_x, i_x_offset ); + i_y = __MAX( p_spu->i_crop_y, i_y_offset ); + i_x_end = __MIN( p_spu->i_crop_x + p_spu->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( p_spu->i_crop_y + p_spu->i_crop_height, i_y_offset + (int)p_fmt->i_visible_height ); p_fmt->i_x_offset = i_x - i_x_offset; @@ -522,28 +553,94 @@ 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 ) + if( p_spu->b_force_alpha && VLC_FOURCC('Y','U','V','P') == + p_spu->p_blend->fmt_in.video.i_chroma ) + { + p_spu->p_blend->fmt_in.video.p_palette->palette[0][3] = + p_spu->pi_alpha[0]; + p_spu->p_blend->fmt_in.video.p_palette->palette[1][3] = + p_spu->pi_alpha[1]; + p_spu->p_blend->fmt_in.video.p_palette->palette[2][3] = + p_spu->pi_alpha[2]; + p_spu->p_blend->fmt_in.video.p_palette->palette[3][3] = + p_spu->pi_alpha[3]; + } + + /* Scale SPU if necessary */ + if( p_region->p_cache ) { - 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]; + 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_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->b_absolute ) + { + i_x_offset = i_x_offset * i_scale_width / 1000; + i_y_offset = i_y_offset * i_scale_height / 1000; + } + + p_spu->p_blend->fmt_in.video = p_region->fmt; /* 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_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; + + 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 ); p_region = p_region->p_next; @@ -552,11 +649,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 @@ -566,8 +663,7 @@ 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; @@ -578,22 +674,21 @@ subpicture_t *vout_SortSubPictures( vout_thread_t *p_vout, * ends with NULL since p_subpic was initialized to NULL. */ for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ ) { - if( p_vout->p_subpicture[i_index].i_status == READY_SUBPICTURE ) + if( p_spu->p_subpicture[i_index].i_status == READY_SUBPICTURE ) { /* 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_type == MEMORY_SUBPICTURE ) { - if( !p_vout->p_subpicture[i_index].b_ephemer - && display_date > p_vout->p_subpicture[i_index].i_stop ) + if( !p_spu->p_subpicture[i_index].b_ephemer + && display_date > p_spu->p_subpicture[i_index].i_stop ) { /* Too late, destroy the subpic */ - vout_DestroySubPicture( p_vout, - &p_vout->p_subpicture[i_index] ); + spu_DestroySubpicture(p_spu,&p_spu->p_subpicture[i_index]); continue; } if( display_date - && display_date < p_vout->p_subpicture[i_index].i_start ) + && display_date < p_spu->p_subpicture[i_index].i_start ) { /* Too early, come back next monday */ continue; @@ -601,22 +696,22 @@ subpicture_t *vout_SortSubPictures( vout_thread_t *p_vout, /* 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_spu->p_subpicture[i_index].b_ephemer ) { if( p_ephemer == NULL ) { - p_ephemer = &p_vout->p_subpicture[i_index]; + p_ephemer = &p_spu->p_subpicture[i_index]; continue; } - if( p_vout->p_subpicture[i_index].i_start + if( p_spu->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]; + p_ephemer = &p_spu->p_subpicture[i_index]; /* If it's the 2nd youngest subpicture, * register its date */ @@ -630,8 +725,8 @@ subpicture_t *vout_SortSubPictures( vout_thread_t *p_vout, } } - 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_subpic; + p_subpic = &p_spu->p_subpicture[i_index]; /* If it's the 2nd youngest subpicture, register its date */ if( !ephemer_date || ephemer_date > p_subpic->i_start ) @@ -642,8 +737,8 @@ subpicture_t *vout_SortSubPictures( vout_thread_t *p_vout, /* If it's not a DVD subpicture, just register it */ else { - 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_subpic; + p_subpic = &p_spu->p_subpicture[i_index]; } } } @@ -655,7 +750,7 @@ subpicture_t *vout_SortSubPictures( vout_thread_t *p_vout, if( p_ephemer->i_start <= ephemer_date ) { /* Ephemer subpicture has lived too long */ - vout_DestroySubPicture( p_vout, p_ephemer ); + spu_DestroySubpicture( p_spu, p_ephemer ); } else { @@ -669,43 +764,21 @@ subpicture_t *vout_SortSubPictures( vout_thread_t *p_vout, } /***************************************************************************** - * vout_RegisterOSDChannel: register an OSD channel + * SpuClearChannel: clear an spu 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 - ***************************************************************************** - * 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; - } - - 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 ) ) @@ -719,44 +792,75 @@ 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. + *****************************************************************************/ +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 * ); + p_spu->i_channel++; + if( pi ) *pi = p_spu->i_channel; + msg_Dbg( p_spu, "Registering subpicture channel, ID: %i", + p_spu->i_channel ); + 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_alpha = 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; + p_spu->i_crop_height = val.i_int - p_spu->i_crop_y; #if 0 if( var_Get( p_object, "color", &val ) == VLC_SUCCESS ) @@ -764,7 +868,7 @@ static void UpdateSPU( vout_thread_t *p_vout, vlc_object_t *p_object ) int i; for( i = 0; i < 4; i++ ) { - p_vout->pi_color[i] = ((uint8_t *)val.p_address)[i]; + p_spu->pi_color[i] = ((uint8_t *)val.p_address)[i]; } } #endif @@ -774,17 +878,16 @@ static void UpdateSPU( vout_thread_t *p_vout, vlc_object_t *p_object ) 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_spu->pi_alpha[i] = ((uint8_t *)val.p_address)[i]; + p_spu->pi_alpha[i] = p_spu->pi_alpha[i] == 0xf ? + 0xff : p_spu->pi_alpha[i] << 4; } - p_vout->b_force_alpha = VLC_TRUE; + p_spu->b_force_alpha = 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, alpha: %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_alpha ); } /***************************************************************************** @@ -795,7 +898,7 @@ 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; } @@ -825,3 +928,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 ); +} -- 2.39.5