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