]> git.sesse.net Git - vlc/blob - modules/video_filter/marq.c
Video filters and outputs strings (Refs:#438)
[vlc] / modules / video_filter / marq.c
1 /*****************************************************************************
2  * marq.c : marquee display video plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2003-2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Mark Moriarty
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc/vout.h>
32
33 #include "vlc_filter.h"
34 #include "vlc_block.h"
35 #include "vlc_osd.h"
36
37 /*****************************************************************************
38  * Local prototypes
39  *****************************************************************************/
40 static int  CreateFilter ( vlc_object_t * );
41 static void DestroyFilter( vlc_object_t * );
42 static subpicture_t *Filter( filter_t *, mtime_t );
43
44
45 static int MarqueeCallback( vlc_object_t *p_this, char const *psz_var,
46                             vlc_value_t oldval, vlc_value_t newval,
47                             void *p_data );
48 static int pi_color_values[] = { 0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
49                0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00,
50                0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080,
51                0x00000080, 0x000000FF, 0x0000FFFF};
52 static char *ppsz_color_descriptions[] = { N_("Default"), N_("Black"),
53                N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"), N_("Red"),
54                N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"),
55                N_("Teal"), N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"),
56                N_("Aqua") };
57
58 /*****************************************************************************
59  * filter_sys_t: marquee filter descriptor
60  *****************************************************************************/
61 struct filter_sys_t
62 {
63     int i_xoff, i_yoff;  /* offsets for the display string in the video window */
64     int i_pos; /* permit relative positioning (top, bottom, left, right, center) */
65     int i_timeout;
66
67     char *psz_marquee;    /* marquee string */
68
69     text_style_t *p_style; /* font control */
70
71     time_t last_time;
72
73     vlc_bool_t b_need_update;
74 };
75
76 #define MSG_TEXT N_("Text")
77 #define MSG_LONGTEXT N_("Marquee text to display")
78 #define POSX_TEXT N_("X offset")
79 #define POSX_LONGTEXT N_("X offset, from the left screen edge" )
80 #define POSY_TEXT N_("Y offset")
81 #define POSY_LONGTEXT N_("Y offset, down from the top" )
82 #define TIMEOUT_TEXT N_("Timeout")
83 #define TIMEOUT_LONGTEXT N_("Number of milliseconds the marquee must remain " \
84                             "display. Default value is " \
85                             "0 (remains forever).")
86 #define OPACITY_TEXT N_("Opacity")
87 #define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \
88     "overlay text. 0 = transparent, 255 = totally opaque. " )
89 #define SIZE_TEXT N_("Font size, pixels")
90 #define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " \
91     "font size)." )
92
93 #define COLOR_TEXT N_("Color")
94 #define COLOR_LONGTEXT N_("Color of the text that will be rendered on "\
95     "the video. This must be an hexadecimal (like HTML colors). The first two "\
96     "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
97     " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
98
99 #define POS_TEXT N_("Marquee position")
100 #define POS_LONGTEXT N_( \
101   "You can enforce the marquee position on the video " \
102   "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
103   "also use combinations of these values, eg 6 = top-right).")
104
105 static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
106 static char *ppsz_pos_descriptions[] =
107      { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
108      N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
109
110 /*****************************************************************************
111  * Module descriptor
112  *****************************************************************************/
113 vlc_module_begin();
114     set_capability( "sub filter", 0 );
115     set_shortname( N_("Marquee" ));
116     set_callbacks( CreateFilter, DestroyFilter );
117     set_category( CAT_VIDEO );
118     set_subcategory( SUBCAT_VIDEO_SUBPIC );
119     add_string( "marq-marquee", "VLC", NULL, MSG_TEXT, MSG_LONGTEXT,
120                 VLC_FALSE );
121
122     set_section( N_("Position"), NULL );
123     add_integer( "marq-x", -1, NULL, POSX_TEXT, POSX_LONGTEXT, VLC_TRUE );
124     add_integer( "marq-y", 0, NULL, POSY_TEXT, POSY_LONGTEXT, VLC_TRUE );
125     add_integer( "marq-position", 5, NULL, POS_TEXT, POS_LONGTEXT, VLC_FALSE );
126
127     set_section( N_("Font"), NULL );
128     /* 5 sets the default to top [1] left [4] */
129     change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
130     add_integer_with_range( "marq-opacity", 255, 0, 255, NULL,
131         OPACITY_TEXT, OPACITY_LONGTEXT, VLC_FALSE );
132     add_integer( "marq-color", 0xFFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
133                   VLC_FALSE );
134         change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
135     add_integer( "marq-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT, VLC_FALSE );
136
137     set_section( N_("Misc"), NULL );
138     add_integer( "marq-timeout", 0, NULL, TIMEOUT_TEXT, TIMEOUT_LONGTEXT,
139                  VLC_FALSE );
140
141     set_description( _("Marquee display sub filter") );
142     add_shortcut( "marq" );
143 vlc_module_end();
144
145 /*****************************************************************************
146  * CreateFilter: allocates marquee video filter
147  *****************************************************************************/
148 static int CreateFilter( vlc_object_t *p_this )
149 {
150     filter_t *p_filter = (filter_t *)p_this;
151     filter_sys_t *p_sys;
152     vlc_object_t *p_input;
153
154     /* Allocate structure */
155     p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
156     if( p_sys == NULL )
157     {
158         msg_Err( p_filter, "out of memory" );
159         return VLC_ENOMEM;
160     }
161
162     /* Hook used for callback variables */
163     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
164     if( !p_input )
165     {
166         return VLC_ENOOBJ;
167     }
168
169     p_sys->p_style = malloc( sizeof( text_style_t ) );
170     memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ) );
171
172     p_sys->i_xoff = var_CreateGetInteger( p_input->p_libvlc , "marq-x" );
173     p_sys->i_yoff = var_CreateGetInteger( p_input->p_libvlc , "marq-y" );
174     p_sys->i_timeout = var_CreateGetInteger( p_input->p_libvlc , "marq-timeout" );
175     p_sys->i_pos = var_CreateGetInteger( p_input->p_libvlc , "marq-position" );
176     p_sys->psz_marquee =  var_CreateGetString( p_input->p_libvlc, "marq-marquee" );
177     p_sys->p_style->i_font_alpha = 255 - var_CreateGetInteger( p_input->p_libvlc , "marq-opacity" );
178     p_sys->p_style->i_font_color = var_CreateGetInteger( p_input->p_libvlc , "marq-color" );
179     p_sys->p_style->i_font_size  = var_CreateGetInteger( p_input->p_libvlc , "marq-size" );
180
181     var_AddCallback( p_input->p_libvlc, "marq-x", MarqueeCallback, p_sys );
182     var_AddCallback( p_input->p_libvlc, "marq-y", MarqueeCallback, p_sys );
183     var_AddCallback( p_input->p_libvlc, "marq-marquee", MarqueeCallback, p_sys );
184     var_AddCallback( p_input->p_libvlc, "marq-timeout", MarqueeCallback, p_sys );
185     var_AddCallback( p_input->p_libvlc, "marq-position", MarqueeCallback, p_sys );
186     var_AddCallback( p_input->p_libvlc, "marq-color", MarqueeCallback, p_sys );
187     var_AddCallback( p_input->p_libvlc, "marq-opacity", MarqueeCallback, p_sys );
188     var_AddCallback( p_input->p_libvlc, "marq-size", MarqueeCallback, p_sys );
189
190     vlc_object_release( p_input );
191
192
193     /* Misc init */
194     p_filter->pf_sub_filter = Filter;
195     p_sys->last_time = ((time_t)-1);
196     p_sys->b_need_update = VLC_TRUE;
197
198     return VLC_SUCCESS;
199 }
200 /*****************************************************************************
201  * DestroyFilter: destroy marquee video filter
202  *****************************************************************************/
203 static void DestroyFilter( vlc_object_t *p_this )
204 {
205     filter_t *p_filter = (filter_t *)p_this;
206     filter_sys_t *p_sys = p_filter->p_sys;
207     vlc_object_t *p_input;
208
209     if( p_sys->p_style ) free( p_sys->p_style );
210     if( p_sys->psz_marquee ) free( p_sys->psz_marquee );
211     free( p_sys );
212
213     /* Delete the marquee variables */
214     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
215     if( !p_input )
216     {
217         return;
218     }
219     var_DelCallback( p_input->p_libvlc, "marq-x", MarqueeCallback, p_sys );
220     var_DelCallback( p_input->p_libvlc, "marq-y", MarqueeCallback, p_sys );
221     var_DelCallback( p_input->p_libvlc, "marq-marquee", MarqueeCallback, p_sys );
222     var_DelCallback( p_input->p_libvlc, "marq-timeout", MarqueeCallback, p_sys );
223     var_DelCallback( p_input->p_libvlc, "marq-position", MarqueeCallback, p_sys );
224     var_DelCallback( p_input->p_libvlc, "marq-color", MarqueeCallback, p_sys );
225     var_DelCallback( p_input->p_libvlc, "marq-opacity", MarqueeCallback, p_sys );
226     var_DelCallback( p_input->p_libvlc, "marq-size", MarqueeCallback, p_sys );
227
228     var_Destroy( p_input->p_libvlc , "marq-marquee" );
229     var_Destroy( p_input->p_libvlc , "marq-x" );
230     var_Destroy( p_input->p_libvlc , "marq-y" );
231     var_Destroy( p_input->p_libvlc , "marq-timeout" );
232     var_Destroy( p_input->p_libvlc , "marq-position" );
233     var_Destroy( p_input->p_libvlc , "marq-color");
234     var_Destroy( p_input->p_libvlc , "marq-opacity");
235     var_Destroy( p_input->p_libvlc , "marq-size");
236
237     vlc_object_release( p_input );
238 }
239
240 /****************************************************************************
241  * Filter: the whole thing
242  ****************************************************************************
243  * This function outputs subpictures at regular time intervals.
244  ****************************************************************************/
245 static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
246 {
247     filter_sys_t *p_sys = p_filter->p_sys;
248     subpicture_t *p_spu;
249     video_format_t fmt;
250     time_t t;
251
252     if( p_sys->last_time == time( NULL ) )
253     {
254         return NULL;
255     }
256
257     if( p_sys->b_need_update == VLC_FALSE )
258     {
259         return NULL;
260     }
261
262     p_spu = p_filter->pf_sub_buffer_new( p_filter );
263     if( !p_spu ) return NULL;
264
265     memset( &fmt, 0, sizeof(video_format_t) );
266     fmt.i_chroma = VLC_FOURCC('T','E','X','T');
267     fmt.i_aspect = 0;
268     fmt.i_width = fmt.i_height = 0;
269     fmt.i_x_offset = 0;
270     fmt.i_y_offset = 0;
271     p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_filter), &fmt );
272     if( !p_spu->p_region )
273     {
274         p_filter->pf_sub_buffer_del( p_filter, p_spu );
275         return NULL;
276     }
277
278     t = p_sys->last_time = time( NULL );
279
280     p_spu->p_region->psz_text = strdup(p_sys->psz_marquee);
281     p_spu->i_start = date;
282     p_spu->i_stop  = p_sys->i_timeout == 0 ? 0 : date + p_sys->i_timeout * 1000;
283     p_spu->b_ephemer = VLC_TRUE;
284
285     /*  where to locate the string: */
286     if( p_sys->i_xoff < 0 || p_sys->i_yoff < 0 )
287     {   /* set to one of the 9 relative locations */
288         p_spu->i_flags = p_sys->i_pos;
289         p_spu->i_x = 0;
290         p_spu->i_y = 0;
291         p_spu->b_absolute = VLC_FALSE;
292     }
293     else
294     {   /*  set to an absolute xy, referenced to upper left corner */
295         p_spu->i_flags = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
296         p_spu->i_x = p_sys->i_xoff;
297         p_spu->i_y = p_sys->i_yoff;
298         p_spu->b_absolute = VLC_TRUE;
299     }
300     p_spu->p_region->p_style = p_sys->p_style;
301
302     p_sys->b_need_update = VLC_FALSE;
303     return p_spu;
304 }
305
306 /**********************************************************************
307  * Callback to update params on the fly
308  **********************************************************************/
309 static int MarqueeCallback( vlc_object_t *p_this, char const *psz_var,
310                             vlc_value_t oldval, vlc_value_t newval,
311                             void *p_data )
312 {
313     filter_sys_t *p_sys = (filter_sys_t *) p_data;
314
315     if( !strncmp( psz_var, "marq-marquee", 7 ) )
316     {
317         if( p_sys->psz_marquee ) free( p_sys->psz_marquee );
318         p_sys->psz_marquee = strdup( newval.psz_string );
319     }
320     else if ( !strncmp( psz_var, "marq-x", 6 ) )
321     {
322         p_sys->i_xoff = newval.i_int;
323     }
324     else if ( !strncmp( psz_var, "marq-y", 6 ) )
325     {
326         p_sys->i_yoff = newval.i_int;
327     }
328     else if ( !strncmp( psz_var, "marq-color", 8 ) )  /* "marq-col" */
329     {
330         p_sys->p_style->i_font_color = newval.i_int;
331     }
332     else if ( !strncmp( psz_var, "marq-opacity", 8 ) ) /* "marq-opa" */
333     {
334         p_sys->p_style->i_font_alpha = 255 - newval.i_int;
335     }
336     else if ( !strncmp( psz_var, "marq-size", 6 ) )
337     {
338         p_sys->p_style->i_font_size = newval.i_int;
339     }
340     else if ( !strncmp( psz_var, "marq-timeout", 12 ) )
341     {
342         p_sys->i_timeout = newval.i_int;
343     }
344     else if ( !strncmp( psz_var, "marq-position", 8 ) )
345     /* willing to accept a match against marq-pos */
346     {
347         p_sys->i_pos = newval.i_int;
348         p_sys->i_xoff = -1;       /* force to relative positioning */
349     }
350     p_sys->b_need_update = VLC_TRUE;
351     return VLC_SUCCESS;
352 }