]> git.sesse.net Git - vlc/blob - modules/video_filter/time.c
* 2nd review of video* and control/telnet.c
[vlc] / modules / video_filter / time.c
1 /*****************************************************************************
2  * time.c : time display video plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2003-2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
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 <time.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/vout.h>
34
35 #include "vlc_filter.h"
36 #include "vlc_block.h"
37 #include "vlc_osd.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 static int TimeCallback( 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: time 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     char        *psz_format;    /* time format string */
65     int         i_pos;          /* permit relative positioning (top, bottom, left, right, center) */
66     text_style_t *p_style;      /* font control */
67
68     time_t last_time;
69 };
70
71 #define MSG_TEXT N_("Time format string (%Y%m%d %H%M%S)")
72 #define MSG_LONGTEXT N_("Time format string (%Y = year, %m = month, %d = day, %H = hour, %M = minute, %S = second).")
73 #define POSX_TEXT N_("X offset")
74 #define POSX_LONGTEXT N_("X offset, from the left screen edge" )
75 #define POSY_TEXT N_("Y offset")
76 #define POSY_LONGTEXT N_("Y offset, down from the top" )
77 #define OPACITY_TEXT N_("Opacity")
78 #define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \
79     "overlay text. 0 = transparent, 255 = totally opaque." )
80
81 #define SIZE_TEXT N_("Font size, pixels")
82 #define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " \
83     "font size)." )
84
85 #define COLOR_TEXT N_("Color")
86 #define COLOR_LONGTEXT N_("Color of the text that will be rendered on "\
87     "the video. This must be an hexadecimal (like HTML colors). The first two "\
88     "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
89     " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
90
91 #define POS_TEXT N_("Text position")
92 #define POS_LONGTEXT N_( \
93   "You can enforce the text position on the video " \
94   "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
95   "also use combinations of these values, e.g. 6 = top-right).")
96
97 static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
98 static char *ppsz_pos_descriptions[] =
99      { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
100      N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
101
102 /*****************************************************************************
103  * Module descriptor
104  *****************************************************************************/
105 vlc_module_begin();
106     set_capability( "sub filter", 0 );
107     set_shortname( N_("Time overlay"));
108     set_category( CAT_VIDEO );
109     set_subcategory( SUBCAT_VIDEO_SUBPIC );
110     set_callbacks( CreateFilter, DestroyFilter );
111     add_string( "time-format", "%Y-%m-%d   %H:%M:%S", NULL, MSG_TEXT,
112                 MSG_LONGTEXT, VLC_TRUE );
113     add_integer( "time-x", -1, NULL, POSX_TEXT, POSX_LONGTEXT, VLC_TRUE );
114     add_integer( "time-y", 0, NULL, POSY_TEXT, POSY_LONGTEXT, VLC_TRUE );
115     add_integer( "time-position", 9, NULL, POS_TEXT, POS_LONGTEXT, VLC_FALSE );
116     /* 9 sets the default to bottom-left, minimizing jitter */
117     change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
118     add_integer_with_range( "time-opacity", 255, 0, 255, NULL,
119         OPACITY_TEXT, OPACITY_LONGTEXT, VLC_FALSE );
120     add_integer( "time-color", 0xFFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
121                  VLC_FALSE );
122         change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
123     add_integer( "time-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT, VLC_FALSE );
124     set_description( _("Time display sub filter") );
125     add_shortcut( "time" );
126 vlc_module_end();
127
128 /*****************************************************************************
129  * CreateFilter: allocates time video filter
130  *****************************************************************************/
131 static int CreateFilter( vlc_object_t *p_this )
132 {
133     filter_t *p_filter = (filter_t *)p_this;
134     filter_sys_t *p_sys;
135     vlc_object_t *p_input;
136
137     /* Allocate structure */
138     p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
139     if( p_sys == NULL )
140     {
141         msg_Err( p_filter, "out of memory" );
142         return VLC_ENOMEM;
143     }
144     /* Hook used for callback variables */
145     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
146     if( !p_input )
147     {
148         return VLC_ENOOBJ;
149     }
150
151     p_sys->p_style = malloc( sizeof( text_style_t ) );
152     memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ) );
153
154     p_sys->i_xoff = var_CreateGetInteger( p_input->p_libvlc , "time-x" );
155     p_sys->i_yoff = var_CreateGetInteger( p_input->p_libvlc , "time-y" );
156     p_sys->psz_format = var_CreateGetString( p_input->p_libvlc, "time-format" );
157     p_sys->i_pos = var_CreateGetInteger( p_input->p_libvlc , "time-position" );
158     
159     p_sys->p_style->i_font_alpha = 255 - var_CreateGetInteger( p_input->p_libvlc , "time-opacity" );
160     p_sys->p_style->i_font_color = var_CreateGetInteger( p_input->p_libvlc , "time-color" );
161     p_sys->p_style->i_font_size = var_CreateGetInteger( p_input->p_libvlc , "time-size" );
162    
163     var_AddCallback( p_input->p_libvlc, "time-x", TimeCallback, p_sys );
164     var_AddCallback( p_input->p_libvlc, "time-y", TimeCallback, p_sys );
165     var_AddCallback( p_input->p_libvlc, "time-format", TimeCallback, p_sys );
166     var_AddCallback( p_input->p_libvlc, "time-position", TimeCallback, p_sys );
167     var_AddCallback( p_input->p_libvlc, "time-color", TimeCallback, p_sys );
168     var_AddCallback( p_input->p_libvlc, "time-opacity", TimeCallback, p_sys );
169     var_AddCallback( p_input->p_libvlc, "time-size", TimeCallback, p_sys );
170
171     vlc_object_release( p_input );
172
173     /* Misc init */
174     p_filter->pf_sub_filter = Filter;
175     p_sys->last_time = ((time_t)-1);
176
177     return VLC_SUCCESS;
178 }
179 /*****************************************************************************
180  * DestroyFilter: destroy logo video filter
181  *****************************************************************************/
182 static void DestroyFilter( vlc_object_t *p_this )
183 {
184     filter_t *p_filter = (filter_t *)p_this;
185     filter_sys_t *p_sys = p_filter->p_sys;
186     vlc_object_t *p_input;
187
188     if( p_sys->p_style ) free( p_sys->p_style );
189     if( p_sys->psz_format ) free( p_sys->psz_format );
190     free( p_sys );
191     /* Delete the time variables */
192     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
193     if( !p_input )
194     {
195         return;
196     }
197     var_Destroy( p_input->p_libvlc , "time-format" );
198     var_Destroy( p_input->p_libvlc , "time-x" );
199     var_Destroy( p_input->p_libvlc , "time-y" );
200     var_Destroy( p_input->p_libvlc , "time-position" );
201     var_Destroy( p_input->p_libvlc , "time-color");
202     var_Destroy( p_input->p_libvlc , "time-opacity");
203     var_Destroy( p_input->p_libvlc , "time-size");
204    
205     vlc_object_release( p_input );
206 }
207
208 static char *FormatTime(char *tformat )
209 {
210   char buffer[255];
211   time_t curtime;
212 #if defined(HAVE_LOCALTIME_R)
213   struct tm loctime;
214 #else
215   struct tm *loctime;
216 #endif
217
218   /* Get the current time.  */
219   curtime = time( NULL );
220
221   /* Convert it to local time representation.  */
222 #if defined(HAVE_LOCALTIME_R)
223   localtime_r( &curtime, &loctime );
224   strftime( buffer, 255, tformat, &loctime );
225 #else
226   loctime = localtime( &curtime );
227   strftime( buffer, 255, tformat, loctime );
228 #endif
229   return strdup( buffer );
230 }
231
232 /****************************************************************************
233  * Filter: the whole thing
234  ****************************************************************************
235  * This function outputs subpictures at regular time intervals.
236  ****************************************************************************/
237 static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
238 {
239     filter_sys_t *p_sys = p_filter->p_sys;
240     subpicture_t *p_spu;
241     video_format_t fmt;
242
243     if( p_sys->last_time == time( NULL ) ) return NULL;
244
245     p_spu = p_filter->pf_sub_buffer_new( p_filter );
246     if( !p_spu ) return NULL;
247
248     memset( &fmt, 0, sizeof(video_format_t) );
249     fmt.i_chroma = VLC_FOURCC('T','E','X','T');
250     fmt.i_aspect = 0;
251     fmt.i_width = fmt.i_height = 0;     
252     fmt.i_x_offset = 0;
253     fmt.i_y_offset = 0;
254     p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_filter), &fmt );
255     if( !p_spu->p_region )
256     {
257         p_filter->pf_sub_buffer_del( p_filter, p_spu );
258         return NULL;
259     }
260
261     p_sys->last_time = time( NULL );
262
263     p_spu->p_region->psz_text = FormatTime( p_sys->psz_format );
264     p_spu->i_start = date;
265     p_spu->i_stop  = 0;
266     p_spu->b_ephemer = VLC_TRUE;
267
268     /*  where to locate the string: */
269     if( p_sys->i_xoff < 0 || p_sys->i_yoff < 0 )
270     {   /* set to one of the 9 relative locations */
271         p_spu->i_flags = p_sys->i_pos;
272         p_spu->i_x = 0;
273         p_spu->i_y = 0;
274         p_spu->b_absolute = VLC_FALSE;
275     }
276     else
277     {   /*  set to an absolute xy, referenced to upper left corner */
278         p_spu->i_flags = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
279         p_spu->i_x = p_sys->i_xoff;
280         p_spu->i_y = p_sys->i_yoff;
281         p_spu->b_absolute = VLC_TRUE;
282     }
283     p_spu->p_region->p_style = p_sys->p_style;
284
285     return p_spu;
286 }
287 /**********************************************************************
288  * Callback to update params on the fly
289  **********************************************************************/
290 static int TimeCallback( 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, "time-format", 11 ) )
297     {
298         if( p_sys->psz_format ) free( p_sys->psz_format );
299         p_sys->psz_format = strdup( newval.psz_string );
300     }
301     else if ( !strncmp( psz_var, "time-x", 6 ) )
302     {
303         p_sys->i_xoff = newval.i_int;
304     }
305     else if ( !strncmp( psz_var, "time-y", 6 ) )
306     {
307         p_sys->i_yoff = newval.i_int;
308     }
309     else if ( !strncmp( psz_var, "time-color", 8 ) )  /* "time-c" */ 
310     {
311         p_sys->p_style->i_font_color = newval.i_int;
312     }
313     else if ( !strncmp( psz_var, "time-opacity", 8 ) ) /* "time-o" */ 
314     {
315         p_sys->p_style->i_font_alpha = 255 - newval.i_int;
316     }
317     else if ( !strncmp( psz_var, "time-size", 6 ) )
318     {
319         p_sys->p_style->i_font_size = newval.i_int;
320     }
321     else if ( !strncmp( psz_var, "time-position", 8 ) )
322     /* willing to accept a match against time-pos */
323     {
324         p_sys->i_pos = newval.i_int;
325         p_sys->i_xoff = -1;       /* force to relative positioning */
326     }
327     return VLC_SUCCESS;
328 }