]> git.sesse.net Git - vlc/blob - modules/video_filter/marq.c
For consistency, remove references to vlc from libvlc
[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                             "displayed. Default value is " \
85                             "0 (remains forever).")
86 #define OPACITY_TEXT N_("Opacity")
87 #define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \
88     "overlayed 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") );
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
153     /* Allocate structure */
154     p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
155     if( p_sys == NULL )
156     {
157         msg_Err( p_filter, "out of memory" );
158         return VLC_ENOMEM;
159     }
160
161     p_sys->p_style = malloc( sizeof( text_style_t ) );
162     memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ) );
163
164     p_sys->i_xoff = var_CreateGetInteger( p_filter->p_libvlc_global , "marq-x" );
165     p_sys->i_yoff = var_CreateGetInteger( p_filter->p_libvlc_global , "marq-y" );
166     p_sys->i_timeout = var_CreateGetInteger( p_filter->p_libvlc_global , "marq-timeout" );
167     p_sys->i_pos = var_CreateGetInteger( p_filter->p_libvlc_global , "marq-position" );
168     p_sys->psz_marquee =  var_CreateGetString( p_filter->p_libvlc_global, "marq-marquee" );
169     p_sys->p_style->i_font_alpha = 255 - var_CreateGetInteger( p_filter->p_libvlc_global , "marq-opacity" );
170     p_sys->p_style->i_font_color = var_CreateGetInteger( p_filter->p_libvlc_global , "marq-color" );
171     p_sys->p_style->i_font_size  = var_CreateGetInteger( p_filter->p_libvlc_global , "marq-size" );
172
173     var_AddCallback( p_filter->p_libvlc_global, "marq-x", MarqueeCallback, p_sys );
174     var_AddCallback( p_filter->p_libvlc_global, "marq-y", MarqueeCallback, p_sys );
175     var_AddCallback( p_filter->p_libvlc_global, "marq-marquee", MarqueeCallback, p_sys );
176     var_AddCallback( p_filter->p_libvlc_global, "marq-timeout", MarqueeCallback, p_sys );
177     var_AddCallback( p_filter->p_libvlc_global, "marq-position", MarqueeCallback, p_sys );
178     var_AddCallback( p_filter->p_libvlc_global, "marq-color", MarqueeCallback, p_sys );
179     var_AddCallback( p_filter->p_libvlc_global, "marq-opacity", MarqueeCallback, p_sys );
180     var_AddCallback( p_filter->p_libvlc_global, "marq-size", MarqueeCallback, p_sys );
181
182     /* Misc init */
183     p_filter->pf_sub_filter = Filter;
184     p_sys->last_time = ((time_t)-1);
185     p_sys->b_need_update = VLC_TRUE;
186
187     return VLC_SUCCESS;
188 }
189 /*****************************************************************************
190  * DestroyFilter: destroy marquee video filter
191  *****************************************************************************/
192 static void DestroyFilter( vlc_object_t *p_this )
193 {
194     filter_t *p_filter = (filter_t *)p_this;
195     filter_sys_t *p_sys = p_filter->p_sys;
196
197     if( p_sys->p_style ) free( p_sys->p_style );
198     if( p_sys->psz_marquee ) free( p_sys->psz_marquee );
199     free( p_sys );
200
201     /* Delete the marquee variables */
202     var_DelCallback( p_filter->p_libvlc_global, "marq-x", MarqueeCallback, p_sys );
203     var_DelCallback( p_filter->p_libvlc_global, "marq-y", MarqueeCallback, p_sys );
204     var_DelCallback( p_filter->p_libvlc_global, "marq-marquee", MarqueeCallback, p_sys );
205     var_DelCallback( p_filter->p_libvlc_global, "marq-timeout", MarqueeCallback, p_sys );
206     var_DelCallback( p_filter->p_libvlc_global, "marq-position", MarqueeCallback, p_sys );
207     var_DelCallback( p_filter->p_libvlc_global, "marq-color", MarqueeCallback, p_sys );
208     var_DelCallback( p_filter->p_libvlc_global, "marq-opacity", MarqueeCallback, p_sys );
209     var_DelCallback( p_filter->p_libvlc_global, "marq-size", MarqueeCallback, p_sys );
210
211     var_Destroy( p_filter->p_libvlc_global , "marq-marquee" );
212     var_Destroy( p_filter->p_libvlc_global , "marq-x" );
213     var_Destroy( p_filter->p_libvlc_global , "marq-y" );
214     var_Destroy( p_filter->p_libvlc_global , "marq-timeout" );
215     var_Destroy( p_filter->p_libvlc_global , "marq-position" );
216     var_Destroy( p_filter->p_libvlc_global , "marq-color");
217     var_Destroy( p_filter->p_libvlc_global , "marq-opacity");
218     var_Destroy( p_filter->p_libvlc_global , "marq-size");
219 }
220
221 /****************************************************************************
222  * Filter: the whole thing
223  ****************************************************************************
224  * This function outputs subpictures at regular time intervals.
225  ****************************************************************************/
226 static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
227 {
228     filter_sys_t *p_sys = p_filter->p_sys;
229     subpicture_t *p_spu;
230     video_format_t fmt;
231     time_t t;
232
233     if( p_sys->last_time == time( NULL ) )
234     {
235         return NULL;
236     }
237
238     if( p_sys->b_need_update == VLC_FALSE )
239     {
240         return NULL;
241     }
242
243     p_spu = p_filter->pf_sub_buffer_new( p_filter );
244     if( !p_spu ) return NULL;
245
246     memset( &fmt, 0, sizeof(video_format_t) );
247     fmt.i_chroma = VLC_FOURCC('T','E','X','T');
248     fmt.i_aspect = 0;
249     fmt.i_width = fmt.i_height = 0;
250     fmt.i_x_offset = 0;
251     fmt.i_y_offset = 0;
252     p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_filter), &fmt );
253     if( !p_spu->p_region )
254     {
255         p_filter->pf_sub_buffer_del( p_filter, p_spu );
256         return NULL;
257     }
258
259     t = p_sys->last_time = time( NULL );
260
261     p_spu->p_region->psz_text = strdup(p_sys->psz_marquee);
262     p_spu->i_start = date;
263     p_spu->i_stop  = p_sys->i_timeout == 0 ? 0 : date + p_sys->i_timeout * 1000;
264     p_spu->b_ephemer = VLC_TRUE;
265
266     /*  where to locate the string: */
267     if( p_sys->i_xoff < 0 || p_sys->i_yoff < 0 )
268     {   /* set to one of the 9 relative locations */
269         p_spu->i_flags = p_sys->i_pos;
270         p_spu->i_x = 0;
271         p_spu->i_y = 0;
272         p_spu->b_absolute = VLC_FALSE;
273     }
274     else
275     {   /*  set to an absolute xy, referenced to upper left corner */
276         p_spu->i_flags = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
277         p_spu->i_x = p_sys->i_xoff;
278         p_spu->i_y = p_sys->i_yoff;
279         p_spu->b_absolute = VLC_TRUE;
280     }
281     p_spu->p_region->p_style = p_sys->p_style;
282
283     p_sys->b_need_update = VLC_FALSE;
284     return p_spu;
285 }
286
287 /**********************************************************************
288  * Callback to update params on the fly
289  **********************************************************************/
290 static int MarqueeCallback( vlc_object_t *p_this, char const *psz_var,
291                             vlc_value_t oldval, vlc_value_t newval,
292                             void *p_data )
293 {
294     filter_sys_t *p_sys = (filter_sys_t *) p_data;
295
296     if( !strncmp( psz_var, "marq-marquee", 7 ) )
297     {
298         if( p_sys->psz_marquee ) free( p_sys->psz_marquee );
299         p_sys->psz_marquee = strdup( newval.psz_string );
300     }
301     else if ( !strncmp( psz_var, "marq-x", 6 ) )
302     {
303         p_sys->i_xoff = newval.i_int;
304     }
305     else if ( !strncmp( psz_var, "marq-y", 6 ) )
306     {
307         p_sys->i_yoff = newval.i_int;
308     }
309     else if ( !strncmp( psz_var, "marq-color", 8 ) )  /* "marq-col" */
310     {
311         p_sys->p_style->i_font_color = newval.i_int;
312     }
313     else if ( !strncmp( psz_var, "marq-opacity", 8 ) ) /* "marq-opa" */
314     {
315         p_sys->p_style->i_font_alpha = 255 - newval.i_int;
316     }
317     else if ( !strncmp( psz_var, "marq-size", 6 ) )
318     {
319         p_sys->p_style->i_font_size = newval.i_int;
320     }
321     else if ( !strncmp( psz_var, "marq-timeout", 12 ) )
322     {
323         p_sys->i_timeout = newval.i_int;
324     }
325     else if ( !strncmp( psz_var, "marq-position", 8 ) )
326     /* willing to accept a match against marq-pos */
327     {
328         p_sys->i_pos = newval.i_int;
329         p_sys->i_xoff = -1;       /* force to relative positioning */
330     }
331     p_sys->b_need_update = VLC_TRUE;
332     return VLC_SUCCESS;
333 }