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