X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fvideo_filter%2Flogo.c;h=4d9149954c2142c39eb902b8e64b14983f3a783a;hb=2a5e51a1bce2cac5453fc4bd42f392120039ed52;hp=60db1c0ead7446aba18f8921c7cd2e7a395964fa;hpb=a782a30580aaf28c5d47914418672f2916571946;p=vlc diff --git a/modules/video_filter/logo.c b/modules/video_filter/logo.c index 60db1c0ead..4d9149954c 100644 --- a/modules/video_filter/logo.c +++ b/modules/video_filter/logo.c @@ -55,6 +55,9 @@ static int Control ( vout_thread_t *, int, va_list ); static int CreateFilter ( vlc_object_t * ); static void DestroyFilter( vlc_object_t * ); +static int LogoCallback( vlc_object_t *, char const *, + vlc_value_t, vlc_value_t, void * ); + /***************************************************************************** * Module descriptor *****************************************************************************/ @@ -67,18 +70,32 @@ static void DestroyFilter( vlc_object_t * ); #define TRANS_TEXT N_("Transparency of the logo") #define TRANS_LONGTEXT N_("You can set the logo transparency value here " \ "(from 0 for full transparency to 255 for full opacity)." ) +#define POS_TEXT N_("Logo position") +#define POS_LONGTEXT N_( \ + "You can enforce the logo position on the video " \ + "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \ + "also use combinations of these values).") + +static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 }; +static char *ppsz_pos_descriptions[] = +{ N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"), + N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") }; vlc_module_begin(); set_description( _("Logo video filter") ); set_capability( "video filter", 0 ); + set_category( CAT_VIDEO ); + set_subcategory( SUBCAT_VIDEO_VFILTER ); add_shortcut( "logo" ); set_callbacks( Create, Destroy ); add_file( "logo-file", NULL, NULL, FILE_TEXT, FILE_LONGTEXT, VLC_FALSE ); - add_integer( "logo-x", 0, NULL, POSX_TEXT, POSX_LONGTEXT, VLC_FALSE ); - add_integer( "logo-y", 0, NULL, POSY_TEXT, POSY_LONGTEXT, VLC_FALSE ); + add_integer( "logo-x", -1, NULL, POSX_TEXT, POSX_LONGTEXT, VLC_FALSE ); + add_integer( "logo-y", -1, NULL, POSY_TEXT, POSY_LONGTEXT, VLC_FALSE ); add_integer_with_range( "logo-transparency", 255, 0, 255, NULL, TRANS_TEXT, TRANS_LONGTEXT, VLC_FALSE ); + add_integer( "logo-position", 6, NULL, POS_TEXT, POS_LONGTEXT, VLC_TRUE ); + change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 ); /* subpicture filter submodule */ add_submodule(); @@ -91,13 +108,12 @@ vlc_module_end(); /***************************************************************************** * LoadPNG: loads the PNG logo into memory *****************************************************************************/ -static picture_t *LoadPNG( vlc_object_t *p_this ) +static picture_t *LoadPNG( vlc_object_t *p_this, char *psz_filename, + int i_trans ) { picture_t *p_pic; - char *psz_filename; - vlc_value_t val; FILE *file; - int i, j, i_trans; + int i, j; vlc_bool_t b_alpha = VLC_TRUE; png_uint_32 i_width, i_height; @@ -107,18 +123,11 @@ static picture_t *LoadPNG( vlc_object_t *p_this ) png_structp p_png; png_infop p_info, p_end_info; - var_Create( p_this, "logo-file", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); - var_Get( p_this, "logo-file", &val ); - psz_filename = val.psz_string; - if( !psz_filename ) return 0; - if( !(file = fopen( psz_filename , "rb" )) ) { - msg_Err( p_this , "logo file (%s) not found", psz_filename ); - free( psz_filename ); + msg_Err( p_this, "logo file (%s) not found", psz_filename ); return 0; } - free( psz_filename ); p_png = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); p_info = png_create_info_struct( p_png ); @@ -140,16 +149,15 @@ static picture_t *LoadPNG( vlc_object_t *p_this ) { png_set_tRNS_to_alpha( p_png ); } - else + else if( !(i_color_type & PNG_COLOR_MASK_ALPHA) ) { b_alpha = VLC_FALSE; } p_row_pointers = malloc( sizeof(png_bytep) * i_height ); for( i = 0; i < (int)i_height; i++ ) - { p_row_pointers[i] = malloc( 4 * ( i_bit_depth + 7 ) / 8 * i_width ); - } + png_read_image( p_png, p_row_pointers ); png_read_end( p_png, p_end_info ); @@ -162,14 +170,11 @@ static picture_t *LoadPNG( vlc_object_t *p_this ) i_width, i_height, VOUT_ASPECT_FACTOR ) != VLC_SUCCESS ) { + for( i = 0; i < (int)i_height; i++ ) free( p_row_pointers[i] ); free( p_row_pointers ); return 0; } - var_Create(p_this, "logo-transparency", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT); - var_Get( p_this, "logo-transparency", &val ); - i_trans = val.i_int; - for( j = 0; j < (int)i_height ; j++ ) { uint8_t *p = (uint8_t *)p_row_pointers[j]; @@ -191,6 +196,7 @@ static picture_t *LoadPNG( vlc_object_t *p_this ) } } + for( i = 0; i < (int)i_height; i++ ) free( p_row_pointers[i] ); free( p_row_pointers ); return p_pic; } @@ -209,7 +215,9 @@ struct vout_sys_t picture_t *p_pic; int i_width, i_height; - int posx, posy; + int pos, posx, posy; + char *psz_filename; + int i_trans; }; /***************************************************************************** @@ -235,15 +243,28 @@ static int Create( vlc_object_t *p_this ) p_vout->pf_render = Render; p_vout->pf_display = NULL; p_vout->pf_control = Control; + + p_sys->psz_filename = var_CreateGetString( p_this , "logo-file" ); + if( !p_sys->psz_filename || !*p_sys->psz_filename ) + { + msg_Err( p_this, "logo file not specified" ); + return 0; + } + var_Create( p_this, "logo-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); + var_Get( p_this, "logo-position", &val ); + p_sys->pos = val.i_int; var_Create( p_this, "logo-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Get( p_this, "logo-x", &val ); p_sys->posx = val.i_int; var_Create( p_this, "logo-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Get( p_this, "logo-y", &val ); p_sys->posy = val.i_int; + var_Create(p_this, "logo-transparency", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT); + var_Get( p_this, "logo-transparency", &val ); + p_sys->i_trans = __MAX( __MIN( val.i_int, 255 ), 0 ); - p_sys->p_pic = LoadPNG( p_this ); + p_sys->p_pic = LoadPNG( p_this, p_sys->psz_filename, p_sys->i_trans ); if( !p_sys->p_pic ) { free( p_sys ); @@ -307,6 +328,29 @@ static int Init( vout_thread_t *p_vout ) return VLC_EGENERIC; } + if( p_sys->posx < 0 || p_sys->posy < 0 ) + { + p_sys->posx = 0; p_sys->posy = 0; + + if( p_sys->pos & SUBPICTURE_ALIGN_BOTTOM ) + { + p_sys->posy = p_vout->render.i_height - p_sys->i_height; + } + else if ( !(p_sys->pos & SUBPICTURE_ALIGN_TOP) ) + { + p_sys->posy = p_vout->render.i_height / 2 - p_sys->i_height / 2; + } + + if( p_sys->pos & SUBPICTURE_ALIGN_RIGHT ) + { + p_sys->posx = p_vout->render.i_width - p_sys->i_width; + } + else if ( !(p_sys->pos & SUBPICTURE_ALIGN_LEFT) ) + { + p_sys->posx = p_vout->render.i_width / 2 - p_sys->i_width / 2; + } + } + /* Try to open the real video output */ msg_Dbg( p_vout, "spawning the real video output" ); @@ -398,7 +442,8 @@ static void Render( vout_thread_t *p_vout, picture_t *p_pic ) vout_DatePicture( p_sys->p_vout, p_outpic, p_pic->date ); p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_outpic, p_outpic, - p_sys->p_pic, p_sys->posx, p_sys->posy ); + p_sys->p_pic, p_sys->posx, p_sys->posy, + 255 ); vout_DisplayPicture( p_sys->p_vout, p_outpic ); } @@ -490,9 +535,17 @@ struct filter_sys_t picture_t *p_pic; int i_width, i_height; - int posx, posy; + int pos, posx, posy; + char *psz_filename; + int i_trans; + + vlc_bool_t b_absolute; mtime_t i_last_date; + + /* On the fly control variable */ + vlc_bool_t b_need_update; + vlc_bool_t b_new_png; }; static subpicture_t *Filter( filter_t *, mtime_t ); @@ -504,7 +557,7 @@ static int CreateFilter( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; filter_sys_t *p_sys; - vlc_value_t val; + vlc_object_t *p_input; /* Allocate structure */ p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) ); @@ -514,27 +567,58 @@ static int CreateFilter( vlc_object_t *p_this ) return VLC_ENOMEM; } - var_Create( p_this, "logo-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); - var_Get( p_this, "logo-x", &val ); - p_sys->posx = val.i_int; - var_Create( p_this, "logo-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); - var_Get( p_this, "logo-y", &val ); - p_sys->posy = val.i_int; + /* Hook used for callback variables */ + p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT ); + if( !p_input ) + { + free( p_sys ); + return VLC_ENOOBJ; + } - p_sys->p_pic = LoadPNG( p_this ); + p_sys->psz_filename = var_CreateGetString( p_input->p_libvlc , "logo-file" ); + if( !p_sys->psz_filename || !*p_sys->psz_filename ) + { + msg_Err( p_this, "logo file not specified" ); + vlc_object_release( p_input ); + free( p_sys ); + return 0; + } + + p_sys->posx = var_CreateGetInteger( p_input->p_libvlc , "logo-x" ); + p_sys->posy = var_CreateGetInteger( p_input->p_libvlc , "logo-y" ); + p_sys->pos = var_CreateGetInteger( p_input->p_libvlc , "logo-position" ); + p_sys->i_trans = var_CreateGetInteger( p_input->p_libvlc, "logo-transparency"); + p_sys->i_trans = __MAX( __MIN( p_sys->i_trans, 255 ), 0 ); + + var_AddCallback( p_input->p_libvlc, "logo-file", LogoCallback, p_sys ); + var_AddCallback( p_input->p_libvlc, "logo-x", LogoCallback, p_sys ); + var_AddCallback( p_input->p_libvlc, "logo-y", LogoCallback, p_sys ); + var_AddCallback( p_input->p_libvlc, "logo-position", LogoCallback, p_sys ); + var_AddCallback( p_input->p_libvlc, "logo-transparency", LogoCallback, p_sys ); + vlc_object_release( p_input ); + + p_sys->b_absolute = VLC_TRUE; + if( p_sys->posx < 0 || p_sys->posy < 0 ) + { + p_sys->b_absolute = VLC_FALSE; + p_sys->posx = 0; p_sys->posy = 0; + } + + p_sys->p_pic = LoadPNG( p_this, p_sys->psz_filename, p_sys->i_trans ); if( !p_sys->p_pic ) { free( p_sys ); return VLC_EGENERIC; } + /* Misc init */ + p_filter->pf_sub_filter = Filter; p_sys->i_width = p_sys->p_pic->p[Y_PLANE].i_visible_pitch; p_sys->i_height = p_sys->p_pic->p[Y_PLANE].i_visible_lines; + p_sys->b_need_update = VLC_TRUE; + p_sys->b_new_png = VLC_FALSE; p_sys->i_last_date = 0; - /* Misc init */ - p_filter->pf_sub_filter = Filter; - return VLC_SUCCESS; } @@ -545,19 +629,31 @@ static void DestroyFilter( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; filter_sys_t *p_sys = p_filter->p_sys; + vlc_object_t *p_input; if( p_sys->p_pic && p_sys->p_pic->p_data_orig ) free( p_sys->p_pic->p_data_orig ); if( p_sys->p_pic ) free( p_sys->p_pic ); free( p_sys ); + + /* Delete the logo variables from INPUT */ + p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT ); + if( !p_input ) return; + + var_Destroy( p_input->p_libvlc , "logo-file" ); + var_Destroy( p_input->p_libvlc , "logo-x" ); + var_Destroy( p_input->p_libvlc , "logo-y" ); + var_Destroy( p_input->p_libvlc , "logo-position" ); + var_Destroy( p_input->p_libvlc , "logo-transparency" ); + vlc_object_release( p_input ); } -/**************************************************************************** +/***************************************************************************** * Filter: the whole thing - **************************************************************************** + ***************************************************************************** * This function outputs subpictures at regular time intervals. - ****************************************************************************/ + *****************************************************************************/ static subpicture_t *Filter( filter_t *p_filter, mtime_t date ) { filter_sys_t *p_sys = p_filter->p_sys; @@ -565,16 +661,49 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date ) subpicture_region_t *p_region; video_format_t fmt; - if( p_sys->i_last_date && p_sys->i_last_date + 5000000 > date ) return 0; + if( !p_sys->b_need_update && p_sys->i_last_date +5000000 > date ) return 0; + + if( p_sys->b_new_png ) + { + if( p_sys->p_pic && p_sys->p_pic->p_data_orig ) + free( p_sys->p_pic->p_data_orig ); + if( p_sys->p_pic ) free( p_sys->p_pic ); + + p_sys->p_pic = LoadPNG( VLC_OBJECT(p_filter), p_sys->psz_filename, + p_sys->i_trans ); + if( p_sys->p_pic ) + { + p_sys->i_width = p_sys->p_pic->p[Y_PLANE].i_visible_pitch; + p_sys->i_height = p_sys->p_pic->p[Y_PLANE].i_visible_lines; + } + + p_sys->b_new_png = VLC_FALSE; + } + + p_sys->b_need_update = VLC_FALSE; /* Allocate the subpicture internal data. */ p_spu = p_filter->pf_sub_buffer_new( p_filter ); if( !p_spu ) return NULL; + p_spu->b_absolute = p_sys->b_absolute; + p_spu->i_start = p_sys->i_last_date = date; + p_spu->i_stop = 0; + p_spu->b_ephemer = VLC_TRUE; + + p_sys->b_need_update = VLC_FALSE; + + if( !p_sys->p_pic || !p_sys->i_trans ) + { + /* Send an empty subpicture to clear the display */ + return p_spu; + } + /* Create new SPU region */ memset( &fmt, 0, sizeof(video_format_t) ); fmt.i_chroma = VLC_FOURCC('Y','U','V','A'); fmt.i_aspect = VOUT_ASPECT_FACTOR; + fmt.i_sar_num = fmt.i_sar_den = 1; fmt.i_width = fmt.i_visible_width = p_sys->i_width; fmt.i_height = fmt.i_visible_height = p_sys->i_height; fmt.i_x_offset = fmt.i_y_offset = 0; @@ -591,11 +720,43 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date ) p_region->i_y = 0; p_spu->i_x = p_sys->posx; p_spu->i_y = p_sys->posy; + p_spu->i_flags = p_sys->pos; p_spu->p_region = p_region; - p_spu->i_start = p_sys->i_last_date = date; - p_spu->i_stop = 0; - p_spu->b_ephemer = VLC_TRUE; - return p_spu; } + +/***************************************************************************** + * Callback to update params on the fly + *****************************************************************************/ +static int LogoCallback( vlc_object_t *p_this, char const *psz_var, + vlc_value_t oldval, vlc_value_t newval, void *p_data ) +{ + filter_sys_t *p_sys = (filter_sys_t *)p_data; + + if( !strncmp( psz_var, "logo-file", 6 ) ) + { + if( p_sys->psz_filename ) free( p_sys->psz_filename ); + p_sys->psz_filename = strdup( newval.psz_string ); + p_sys->b_new_png = VLC_TRUE; + } + else if ( !strncmp( psz_var, "logo-x", 6 ) ) + { + p_sys->posx = newval.i_int; + } + else if ( !strncmp( psz_var, "logo-y", 6 ) ) + { + p_sys->posy = newval.i_int; + } + else if ( !strncmp( psz_var, "logo-position", 12 ) ) + { + p_sys->pos = newval.i_int; + } + else if ( !strncmp( psz_var, "logo-transparency", 9 ) ) + { + p_sys->i_trans = __MAX( __MIN( newval.i_int, 255 ), 0 ); + p_sys->b_new_png = VLC_TRUE; + } + p_sys->b_need_update = VLC_TRUE; + return VLC_SUCCESS; +}