]> git.sesse.net Git - vlc/blob - src/video_output/vout_intf.c
Show title on video output based on users preferences. Defaults are:--video-title...
[vlc] / src / video_output / vout_intf.c
1 /*****************************************************************************
2  * vout_intf.c : video output interface
3  *****************************************************************************
4  * Copyright (C) 2000-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@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
28 #include <vlc/vlc.h>
29
30 #include <stdio.h>
31 #include <stdlib.h>                                                /* free() */
32 #include <sys/types.h>                                          /* opendir() */
33 #include <dirent.h>                                             /* opendir() */
34
35 #include <vlc_interface.h>
36 #include <vlc_block.h>
37 #include <vlc_playlist.h>
38
39 #include <vlc_vout.h>
40 #include <vlc_image.h>
41 #include <vlc_osd.h>
42 #include <vlc_charset.h>
43
44 #include <vlc_strings.h>
45 #include <vlc_charset.h>
46
47 /*****************************************************************************
48  * Local prototypes
49  *****************************************************************************/
50 static void InitWindowSize( vout_thread_t *, unsigned *, unsigned * );
51
52 /* Object variables callbacks */
53 static int ZoomCallback( vlc_object_t *, char const *,
54                          vlc_value_t, vlc_value_t, void * );
55 static int CropCallback( vlc_object_t *, char const *,
56                          vlc_value_t, vlc_value_t, void * );
57 static int AspectCallback( vlc_object_t *, char const *,
58                            vlc_value_t, vlc_value_t, void * );
59 static int OnTopCallback( vlc_object_t *, char const *,
60                           vlc_value_t, vlc_value_t, void * );
61 static int FullscreenCallback( vlc_object_t *, char const *,
62                                vlc_value_t, vlc_value_t, void * );
63 static int SnapshotCallback( vlc_object_t *, char const *,
64                              vlc_value_t, vlc_value_t, void * );
65 static int TitleCallback( vlc_object_t *, char const *,
66                        vlc_value_t, vlc_value_t, void * );
67
68 /*****************************************************************************
69  * vout_RequestWindow: Create/Get a video window if possible.
70  *****************************************************************************
71  * This function looks for the main interface and tries to request
72  * a new video window. If it fails then the vout will still need to create the
73  * window by itself.
74  *****************************************************************************/
75 void *vout_RequestWindow( vout_thread_t *p_vout,
76                           int *pi_x_hint, int *pi_y_hint,
77                           unsigned int *pi_width_hint,
78                           unsigned int *pi_height_hint )
79 {
80     intf_thread_t *p_intf = NULL;
81     vlc_list_t *p_list;
82     void *p_window;
83     vlc_value_t val;
84     int i;
85
86     /* Small kludge */
87     if( !var_Type( p_vout, "aspect-ratio" ) ) vout_IntfInit( p_vout );
88
89     /* Get requested coordinates */
90     var_Get( p_vout, "video-x", &val );
91     *pi_x_hint = val.i_int ;
92     var_Get( p_vout, "video-y", &val );
93     *pi_y_hint = val.i_int;
94
95     *pi_width_hint = p_vout->i_window_width;
96     *pi_height_hint = p_vout->i_window_height;
97
98     /* Check whether someone provided us with a window ID */
99     var_Get( p_vout->p_libvlc, "drawable", &val );
100     if( val.i_int ) return (void *)val.i_int;
101
102     /* Find if the main interface supports embedding */
103     p_list = vlc_list_find( p_vout, VLC_OBJECT_INTF, FIND_ANYWHERE );
104     if( !p_list ) return NULL;
105
106     for( i = 0; i < p_list->i_count; i++ )
107     {
108         p_intf = (intf_thread_t *)p_list->p_values[i].p_object;
109         if( p_intf->b_block && p_intf->pf_request_window ) break;
110         p_intf = NULL;
111     }
112
113     if( !p_intf )
114     {
115         vlc_list_release( p_list );
116         return NULL;
117     }
118
119     vlc_object_yield( p_intf );
120     vlc_list_release( p_list );
121
122     p_window = p_intf->pf_request_window( p_intf, p_vout, pi_x_hint, pi_y_hint,
123                                           pi_width_hint, pi_height_hint );
124
125     if( !p_window ) vlc_object_release( p_intf );
126     else p_vout->p_parent_intf = p_intf;
127
128     return p_window;
129 }
130
131 void vout_ReleaseWindow( vout_thread_t *p_vout, void *p_window )
132 {
133     intf_thread_t *p_intf = p_vout->p_parent_intf;
134
135     if( !p_intf ) return;
136
137     vlc_mutex_lock( &p_intf->object_lock );
138     if( p_intf->b_dead )
139     {
140         vlc_mutex_unlock( &p_intf->object_lock );
141         return;
142     }
143
144     if( !p_intf->pf_release_window )
145     {
146         msg_Err( p_vout, "no pf_release_window");
147         vlc_mutex_unlock( &p_intf->object_lock );
148         vlc_object_release( p_intf );
149         return;
150     }
151
152     p_intf->pf_release_window( p_intf, p_window );
153
154     p_vout->p_parent_intf = NULL;
155     vlc_mutex_unlock( &p_intf->object_lock );
156     vlc_object_release( p_intf );
157 }
158
159 int vout_ControlWindow( vout_thread_t *p_vout, void *p_window,
160                         int i_query, va_list args )
161 {
162     intf_thread_t *p_intf = p_vout->p_parent_intf;
163     int i_ret;
164
165     if( !p_intf ) return VLC_EGENERIC;
166
167     vlc_mutex_lock( &p_intf->object_lock );
168     if( p_intf->b_dead )
169     {
170         vlc_mutex_unlock( &p_intf->object_lock );
171         return VLC_EGENERIC;
172     }
173
174     if( !p_intf->pf_control_window )
175     {
176         msg_Err( p_vout, "no pf_control_window");
177         vlc_mutex_unlock( &p_intf->object_lock );
178         return VLC_EGENERIC;
179     }
180
181     i_ret = p_intf->pf_control_window( p_intf, p_window, i_query, args );
182     vlc_mutex_unlock( &p_intf->object_lock );
183     return i_ret;
184 }
185
186 /*****************************************************************************
187  * vout_IntfInit: called during the vout creation to initialise misc things.
188  *****************************************************************************/
189 void vout_IntfInit( vout_thread_t *p_vout )
190 {
191     vlc_value_t val, text, old_val;
192     vlc_bool_t b_force_par = VLC_FALSE;
193     char *psz_buf;
194
195     /* Create a few object variables we'll need later on */
196     var_Create( p_vout, "snapshot-path", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
197     var_Create( p_vout, "snapshot-prefix", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
198     var_Create( p_vout, "snapshot-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
199     var_Create( p_vout, "snapshot-preview", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
200     var_Create( p_vout, "snapshot-sequential",
201                 VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
202     var_Create( p_vout, "snapshot-num", VLC_VAR_INTEGER );
203     var_SetInteger( p_vout, "snapshot-num", 1 );
204
205     var_Create( p_vout, "width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
206     var_Create( p_vout, "height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
207     var_Create( p_vout, "align", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
208     var_Get( p_vout, "align", &val );
209     p_vout->i_alignment = val.i_int;
210
211     var_Create( p_vout, "video-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
212     var_Create( p_vout, "video-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
213
214     var_Create( p_vout, "video-title-show", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
215     var_Create( p_vout, "video-title-timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
216     var_Create( p_vout, "video-title-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
217
218     p_vout->b_title_show = var_GetBool( p_vout, "video-title-show" );
219     p_vout->i_title_timeout = (mtime_t) var_GetInteger( p_vout, "video-title-timeout" );
220     p_vout->i_title_position = var_GetInteger( p_vout, "video-title-position" );
221
222     var_AddCallback( p_vout, "video-title-show", TitleCallback, NULL );
223     var_AddCallback( p_vout, "video-title-timeout", TitleCallback, NULL );
224     var_AddCallback( p_vout, "video-title-position", TitleCallback, NULL );
225
226     /* Zoom object var */
227     var_Create( p_vout, "zoom", VLC_VAR_FLOAT | VLC_VAR_ISCOMMAND |
228                 VLC_VAR_HASCHOICE | VLC_VAR_DOINHERIT );
229
230     text.psz_string = _("Zoom");
231     var_Change( p_vout, "zoom", VLC_VAR_SETTEXT, &text, NULL );
232
233     var_Get( p_vout, "zoom", &old_val );
234     if( old_val.f_float == 0.25 ||
235         old_val.f_float == 0.5 ||
236         old_val.f_float == 1 ||
237         old_val.f_float == 2 )
238     {
239         var_Change( p_vout, "zoom", VLC_VAR_DELCHOICE, &old_val, NULL );
240     }
241
242     val.f_float = 0.25; text.psz_string = _("1:4 Quarter");
243     var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, &val, &text );
244     val.f_float = 0.5; text.psz_string = _("1:2 Half");
245     var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, &val, &text );
246     val.f_float = 1; text.psz_string = _("1:1 Original");
247     var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, &val, &text );
248     val.f_float = 2; text.psz_string = _("2:1 Double");
249     var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, &val, &text );
250
251     var_Set( p_vout, "zoom", old_val );
252
253     var_AddCallback( p_vout, "zoom", ZoomCallback, NULL );
254
255     /* Crop offset vars */
256     var_Create( p_vout, "crop-left", VLC_VAR_INTEGER );
257     var_Create( p_vout, "crop-top", VLC_VAR_INTEGER );
258     var_Create( p_vout, "crop-right", VLC_VAR_INTEGER );
259     var_Create( p_vout, "crop-bottom", VLC_VAR_INTEGER );
260
261     var_SetInteger( p_vout, "crop-left", 0 );
262     var_SetInteger( p_vout, "crop-top", 0 );
263     var_SetInteger( p_vout, "crop-right", 0 );
264     var_SetInteger( p_vout, "crop-bottom", 0 );
265
266     var_AddCallback( p_vout, "crop-left", CropCallback, NULL );
267     var_AddCallback( p_vout, "crop-top", CropCallback, NULL );
268     var_AddCallback( p_vout, "crop-right", CropCallback, NULL );
269     var_AddCallback( p_vout, "crop-bottom", CropCallback, NULL );
270
271     /* Crop object var */
272     var_Create( p_vout, "crop", VLC_VAR_STRING |
273                 VLC_VAR_HASCHOICE | VLC_VAR_DOINHERIT );
274
275     text.psz_string = _("Crop");
276     var_Change( p_vout, "crop", VLC_VAR_SETTEXT, &text, NULL );
277
278     val.psz_string = "";
279     var_Change( p_vout, "crop", VLC_VAR_DELCHOICE, &val, 0 );
280     val.psz_string = ""; text.psz_string = _("Default");
281     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
282     val.psz_string = "1:1"; text.psz_string = "1:1";
283     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
284     val.psz_string = "4:3"; text.psz_string = "4:3";
285     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
286     val.psz_string = "16:9"; text.psz_string = "16:9";
287     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
288     val.psz_string = "16:10"; text.psz_string = "16:10";
289     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
290     val.psz_string = "5:4"; text.psz_string = "5:4";
291     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
292     val.psz_string = "5:3"; text.psz_string = "5:3";
293     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
294     val.psz_string = "1.85:1"; text.psz_string = "1.85:1";
295     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
296     val.psz_string = "221:100"; text.psz_string = "2.21:1";
297     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
298     val.psz_string = "235:100"; text.psz_string = "2.35:1";
299     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
300     val.psz_string = "239:100"; text.psz_string = "2.39:1";
301     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
302
303     /* Add custom crop ratios */
304     psz_buf = config_GetPsz( p_vout, "custom-crop-ratios" );
305     if( psz_buf && *psz_buf )
306     {
307         char *psz_cur = psz_buf;
308         char *psz_next;
309         while( psz_cur && *psz_cur )
310         {
311             psz_next = strchr( psz_cur, ',' );
312             if( psz_next )
313             {
314                 *psz_next = '\0';
315                 psz_next++;
316             }
317             val.psz_string = strdup( psz_cur );
318             text.psz_string = strdup( psz_cur );
319             var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text);
320             free( val.psz_string );
321             free( text.psz_string );
322             psz_cur = psz_next;
323         }
324     }
325     if( psz_buf ) free( psz_buf );
326
327     var_AddCallback( p_vout, "crop", CropCallback, NULL );
328     var_Get( p_vout, "crop", &old_val );
329     if( old_val.psz_string && *old_val.psz_string )
330         var_Change( p_vout, "crop", VLC_VAR_TRIGGER_CALLBACKS, 0, 0 );
331     if( old_val.psz_string ) free( old_val.psz_string );
332
333     /* Monitor pixel aspect-ratio */
334     var_Create( p_vout, "monitor-par", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
335     var_Get( p_vout, "monitor-par", &val );
336     if( val.psz_string && *val.psz_string )
337     {
338         char *psz_parser = strchr( val.psz_string, ':' );
339         unsigned int i_aspect_num = 0, i_aspect_den = 0;
340         float i_aspect = 0;
341         if( psz_parser )
342         {
343             i_aspect_num = strtol( val.psz_string, 0, 10 );
344             i_aspect_den = strtol( ++psz_parser, 0, 10 );
345         }
346         else
347         {
348             i_aspect = atof( val.psz_string );
349             vlc_ureduce( &i_aspect_num, &i_aspect_den,
350                          i_aspect *VOUT_ASPECT_FACTOR, VOUT_ASPECT_FACTOR, 0 );
351         }
352         if( !i_aspect_num || !i_aspect_den ) i_aspect_num = i_aspect_den = 1;
353
354         p_vout->i_par_num = i_aspect_num;
355         p_vout->i_par_den = i_aspect_den;
356
357         vlc_ureduce( &p_vout->i_par_num, &p_vout->i_par_den,
358                      p_vout->i_par_num, p_vout->i_par_den, 0 );
359
360         msg_Dbg( p_vout, "overriding monitor pixel aspect-ratio: %i:%i",
361                  p_vout->i_par_num, p_vout->i_par_den );
362         b_force_par = VLC_TRUE;
363     }
364     if( val.psz_string ) free( val.psz_string );
365
366     /* Aspect-ratio object var */
367     var_Create( p_vout, "aspect-ratio", VLC_VAR_STRING |
368                 VLC_VAR_HASCHOICE | VLC_VAR_DOINHERIT );
369
370     text.psz_string = _("Aspect-ratio");
371     var_Change( p_vout, "aspect-ratio", VLC_VAR_SETTEXT, &text, NULL );
372
373     val.psz_string = "";
374     var_Change( p_vout, "aspect-ratio", VLC_VAR_DELCHOICE, &val, 0 );
375     val.psz_string = ""; text.psz_string = _("Default");
376     var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
377     val.psz_string = "1:1"; text.psz_string = "1:1";
378     var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
379     val.psz_string = "4:3"; text.psz_string = "4:3";
380     var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
381     val.psz_string = "16:9"; text.psz_string = "16:9";
382     var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
383     val.psz_string = "16:10"; text.psz_string = "16:10";
384     var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
385     val.psz_string = "221:100"; text.psz_string = "2.21:1";
386     var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
387     val.psz_string = "5:4"; text.psz_string = "5:4";
388     var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
389
390     /* Add custom aspect ratios */
391     psz_buf = config_GetPsz( p_vout, "custom-aspect-ratios" );
392     if( psz_buf && *psz_buf )
393     {
394         char *psz_cur = psz_buf;
395         char *psz_next;
396         while( psz_cur && *psz_cur )
397         {
398             psz_next = strchr( psz_cur, ',' );
399             if( psz_next )
400             {
401                 *psz_next = '\0';
402                 psz_next++;
403             }
404             val.psz_string = strdup( psz_cur );
405             text.psz_string = strdup( psz_cur );
406             var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text);
407             free( val.psz_string );
408             free( text.psz_string );
409             psz_cur = psz_next;
410         }
411     }
412     if( psz_buf ) free( psz_buf );
413
414     var_AddCallback( p_vout, "aspect-ratio", AspectCallback, NULL );
415     var_Get( p_vout, "aspect-ratio", &old_val );
416     if( (old_val.psz_string && *old_val.psz_string) || b_force_par )
417         var_Change( p_vout, "aspect-ratio", VLC_VAR_TRIGGER_CALLBACKS, 0, 0 );
418     if( old_val.psz_string ) free( old_val.psz_string );
419
420     /* Initialize the dimensions of the video window */
421     InitWindowSize( p_vout, &p_vout->i_window_width,
422                     &p_vout->i_window_height );
423
424     /* Add a variable to indicate if the window should be on top of others */
425     var_Create( p_vout, "video-on-top", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
426     text.psz_string = _("Always on top");
427     var_Change( p_vout, "video-on-top", VLC_VAR_SETTEXT, &text, NULL );
428     var_AddCallback( p_vout, "video-on-top", OnTopCallback, NULL );
429
430     /* Add a variable to indicate whether we want window decoration or not */
431     var_Create( p_vout, "video-deco", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
432
433     /* Add a fullscreen variable */
434     var_Create( p_vout, "fullscreen", VLC_VAR_BOOL );
435     text.psz_string = _("Fullscreen");
436     var_Change( p_vout, "fullscreen", VLC_VAR_SETTEXT, &text, NULL );
437     var_Change( p_vout, "fullscreen", VLC_VAR_INHERITVALUE, &val, NULL );
438     if( val.b_bool )
439     {
440         /* user requested fullscreen */
441         p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
442     }
443     var_AddCallback( p_vout, "fullscreen", FullscreenCallback, NULL );
444
445     /* Add a snapshot variable */
446     var_Create( p_vout, "video-snapshot", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
447     text.psz_string = _("Snapshot");
448     var_Change( p_vout, "video-snapshot", VLC_VAR_SETTEXT, &text, NULL );
449     var_AddCallback( p_vout, "video-snapshot", SnapshotCallback, NULL );
450
451     /* Mouse coordinates */
452     var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
453     var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER );
454     var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
455     var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL );
456     var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER );
457
458     var_Create( p_vout, "intf-change", VLC_VAR_BOOL );
459     val.b_bool = VLC_TRUE;
460     var_Set( p_vout, "intf-change", val );
461 }
462
463 /*****************************************************************************
464  * vout_Snapshot: generates a snapshot.
465  *****************************************************************************/
466 int vout_Snapshot( vout_thread_t *p_vout, picture_t *p_pic )
467 {
468     image_handler_t *p_image = image_HandlerCreate( p_vout );
469     video_format_t fmt_in, fmt_out;
470     char *psz_filename = NULL;
471     subpicture_t *p_subpic;
472     picture_t *p_pif;
473     vlc_value_t val, format;
474     DIR *path;
475     int i_ret;
476
477     memset( &fmt_in, 0, sizeof(video_format_t));
478     memset( &fmt_out, 0, sizeof(video_format_t));
479
480     var_Get( p_vout, "snapshot-path", &val );
481     if( val.psz_string && !*val.psz_string )
482     {
483         free( val.psz_string );
484         val.psz_string = 0;
485     }
486
487     /* Embedded snapshot : if snapshot-path == object:object-id, then
488        create a snapshot_t* and store it in
489        object(object-id)->p_private, then unlock and signal the
490        waiting object.
491      */
492     if( val.psz_string && !strncmp( val.psz_string, "object:", 7 ) )
493     {
494         int i_id;
495         vlc_object_t* p_dest;
496         block_t *p_block;
497         snapshot_t *p_snapshot;
498         int i_size;
499
500         /* Destination object-id is following object: */
501         i_id = atoi( &val.psz_string[7] );
502         p_dest = ( vlc_object_t* )vlc_current_object( i_id );
503         if( !p_dest )
504         {
505             msg_Err( p_vout, "Cannot find calling object" );
506             image_HandlerDelete( p_image );
507             return VLC_EGENERIC;
508         }
509         /* Object must be locked. We will unlock it once we get the
510            snapshot and written it to p_private */
511         p_dest->p_private = NULL;
512
513         /* Save the snapshot to a memory zone */
514         fmt_in = p_vout->fmt_in;
515         fmt_out.i_sar_num = fmt_out.i_sar_den = 1;
516         /* FIXME: should not be hardcoded. We should be able to
517         specify the snapshot size (snapshot-width and snapshot-height). */
518         fmt_out.i_width = 320;
519         fmt_out.i_height = 200;
520         fmt_out.i_chroma = VLC_FOURCC( 'p','n','g',' ' );
521         p_block = ( block_t* ) image_Write( p_image, p_pic, &fmt_in, &fmt_out );
522         if( !p_block )
523         {
524             msg_Err( p_vout, "Could not get snapshot" );
525             image_HandlerDelete( p_image );
526             vlc_cond_signal( &p_dest->object_wait );
527             vlc_mutex_unlock( &p_dest->object_lock );
528             vlc_object_release( p_dest );
529             return VLC_EGENERIC;
530         }
531
532         /* Copy the p_block data to a snapshot structure */
533         /* FIXME: get the timestamp */
534         p_snapshot = ( snapshot_t* ) malloc( sizeof( snapshot_t ) );
535         if( !p_snapshot )
536         {
537             block_Release( p_block );
538             image_HandlerDelete( p_image );
539             vlc_cond_signal( &p_dest->object_wait );
540             vlc_mutex_unlock( &p_dest->object_lock );
541             vlc_object_release( p_dest );
542             return VLC_ENOMEM;
543         }
544
545         i_size = p_block->i_buffer;
546
547         p_snapshot->i_width = fmt_out.i_width;
548         p_snapshot->i_height = fmt_out.i_height;
549         p_snapshot->i_datasize = i_size;
550         p_snapshot->date = p_block->i_pts; /* FIXME ?? */
551         p_snapshot->p_data = ( char* ) malloc( i_size );
552         if( !p_snapshot->p_data )
553         {
554             block_Release( p_block );
555             free( p_snapshot );
556             image_HandlerDelete( p_image );
557             vlc_cond_signal( &p_dest->object_wait );
558             vlc_mutex_unlock( &p_dest->object_lock );
559             vlc_object_release( p_dest );
560             return VLC_ENOMEM;
561         }
562         memcpy( p_snapshot->p_data, p_block->p_buffer, p_block->i_buffer );
563
564         p_dest->p_private = p_snapshot;
565
566         block_Release( p_block );
567
568         /* Unlock the object */
569         vlc_cond_signal( &p_dest->object_wait );
570         vlc_mutex_unlock( &p_dest->object_lock );
571         vlc_object_release( p_dest );
572
573         image_HandlerDelete( p_image );
574         return VLC_SUCCESS;
575     }
576
577
578 #if defined(__APPLE__) || defined(SYS_BEOS)
579     if( !val.psz_string && p_vout->p_libvlc->psz_homedir )
580     {
581         asprintf( &val.psz_string, "%s/Desktop",
582                   p_vout->p_libvlc->psz_homedir );
583     }
584
585 #elif defined(WIN32) && !defined(UNDER_CE)
586     if( !val.psz_string && p_vout->p_libvlc->psz_homedir )
587     {
588         /* Get the My Pictures folder path */
589
590         char *p_mypicturesdir = NULL;
591         typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD,
592                                                    LPWSTR );
593         #ifndef CSIDL_FLAG_CREATE
594         #   define CSIDL_FLAG_CREATE 0x8000
595         #endif
596         #ifndef CSIDL_MYPICTURES
597         #   define CSIDL_MYPICTURES 0x27
598         #endif
599         #ifndef SHGFP_TYPE_CURRENT
600         #   define SHGFP_TYPE_CURRENT 0
601         #endif
602
603         HINSTANCE shfolder_dll;
604         SHGETFOLDERPATH SHGetFolderPath ;
605
606         /* load the shfolder dll to retrieve SHGetFolderPath */
607         if( ( shfolder_dll = LoadLibrary( _T("SHFolder.dll") ) ) != NULL )
608         {
609            wchar_t wdir[PATH_MAX];
610            SHGetFolderPath = (void *)GetProcAddress( shfolder_dll,
611                                                       _T("SHGetFolderPathW") );
612             if ((SHGetFolderPath != NULL )
613              && SUCCEEDED (SHGetFolderPath (NULL,
614                                            CSIDL_MYPICTURES | CSIDL_FLAG_CREATE,
615                                            NULL, SHGFP_TYPE_CURRENT,
616                                            wdir)))
617                 p_mypicturesdir = FromWide (wdir);
618
619             FreeLibrary( shfolder_dll );
620         }
621
622         if( p_mypicturesdir == NULL )
623         {
624             asprintf( &val.psz_string, "%s\\" CONFIG_DIR,
625                       p_vout->p_libvlc->psz_homedir );
626         }
627         else
628         {
629             asprintf( &val.psz_string, p_mypicturesdir );
630             free( p_mypicturesdir );
631         }
632     }
633
634 #else
635     if( !val.psz_string && p_vout->p_libvlc->psz_homedir )
636     {
637         asprintf( &val.psz_string, "%s/" CONFIG_DIR,
638                   p_vout->p_libvlc->psz_homedir );
639     }
640 #endif
641
642     if( !val.psz_string )
643     {
644         msg_Err( p_vout, "no path specified for snapshots" );
645         return VLC_EGENERIC;
646     }
647     var_Get( p_vout, "snapshot-format", &format );
648     if( !format.psz_string || !*format.psz_string )
649     {
650         if( format.psz_string ) free( format.psz_string );
651         format.psz_string = strdup( "png" );
652     }
653
654     /*
655      * Did the user specify a directory? If not, path = NULL.
656      */
657     path = utf8_opendir ( (const char *)val.psz_string  );
658
659     if ( path != NULL )
660     {
661         char *psz_prefix = var_GetString( p_vout, "snapshot-prefix" );
662         if( !psz_prefix ) psz_prefix = strdup( "vlcsnap-" );
663         else
664         {
665             char *psz_tmp = str_format( p_vout, psz_prefix );
666             filename_sanitize( psz_tmp );
667             free( psz_prefix );
668             psz_prefix = psz_tmp;
669         }
670
671         closedir( path );
672         if( var_GetBool( p_vout, "snapshot-sequential" ) == VLC_TRUE )
673         {
674             int i_num = var_GetInteger( p_vout, "snapshot-num" );
675             FILE *p_file;
676             do
677             {
678                 asprintf( &psz_filename, "%s" DIR_SEP "%s%05d.%s", val.psz_string,
679                           psz_prefix, i_num++, format.psz_string );
680             }
681             while( ( p_file = utf8_fopen( psz_filename, "r" ) ) && !fclose( p_file ) );
682             var_SetInteger( p_vout, "snapshot-num", i_num );
683         }
684         else
685         {
686             asprintf( &psz_filename, "%s" DIR_SEP "%s%u.%s", val.psz_string,
687                       psz_prefix,
688                       (unsigned int)(p_pic->date / 100000) & 0xFFFFFF,
689                       format.psz_string );
690         }
691
692         free( psz_prefix );
693     }
694     else // The user specified a full path name (including file name)
695     {
696         psz_filename = str_format( p_vout, val.psz_string );
697         path_sanitize( psz_filename );
698     }
699
700     free( val.psz_string );
701     free( format.psz_string );
702
703     /* Save the snapshot */
704     fmt_in = p_vout->fmt_in;
705     fmt_out.i_sar_num = fmt_out.i_sar_den = 1;
706     i_ret = image_WriteUrl( p_image, p_pic, &fmt_in, &fmt_out, psz_filename );
707     if( i_ret != VLC_SUCCESS )
708     {
709         msg_Err( p_vout, "could not create snapshot %s", psz_filename );
710         free( psz_filename );
711         image_HandlerDelete( p_image );
712         return VLC_EGENERIC;
713     }
714
715     msg_Dbg( p_vout, "snapshot taken (%s)", psz_filename );
716     vout_OSDMessage( VLC_OBJECT( p_vout ), DEFAULT_CHAN,
717                      "%s", psz_filename );
718     free( psz_filename );
719
720     if( var_GetBool( p_vout, "snapshot-preview" ) )
721     {
722         /* Inject a subpicture with the snapshot */
723         memset( &fmt_out, 0, sizeof(fmt_out) );
724         fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
725         p_pif = image_Convert( p_image, p_pic, &fmt_in, &fmt_out );
726         image_HandlerDelete( p_image );
727         if( !p_pif ) return VLC_EGENERIC;
728
729         p_subpic = spu_CreateSubpicture( p_vout->p_spu );
730         if( p_subpic == NULL )
731         {
732              p_pif->pf_release( p_pif );
733              return VLC_EGENERIC;
734         }
735
736         p_subpic->i_channel = 0;
737         p_subpic->i_start = mdate();
738         p_subpic->i_stop = mdate() + 4000000;
739         p_subpic->b_ephemer = VLC_TRUE;
740         p_subpic->b_fade = VLC_TRUE;
741         p_subpic->i_original_picture_width = p_vout->render.i_width * 4;
742         p_subpic->i_original_picture_height = p_vout->render.i_height * 4;
743
744         p_subpic->p_region = spu_CreateRegion( p_vout->p_spu, &fmt_out );
745         vout_CopyPicture( p_image->p_parent, &p_subpic->p_region->picture,
746                           p_pif );
747         p_pif->pf_release( p_pif );
748
749         spu_DisplaySubpicture( p_vout->p_spu, p_subpic );
750     }
751     else
752     {
753         image_HandlerDelete( p_image );
754     }
755
756     return VLC_SUCCESS;
757 }
758
759 /*****************************************************************************
760  * Handle filters
761  *****************************************************************************/
762
763 void vout_EnableFilter( vout_thread_t *p_vout, char *psz_name,
764                         vlc_bool_t b_add, vlc_bool_t b_setconfig )
765 {
766     char *psz_parser;
767     char *psz_string = config_GetPsz( p_vout, "vout-filter" );
768
769     /* Todo : Use some generic chain manipulation functions */
770     if( !psz_string ) psz_string = strdup("");
771
772     psz_parser = strstr( psz_string, psz_name );
773     if( b_add )
774     {
775         if( !psz_parser )
776         {
777             psz_parser = psz_string;
778             asprintf( &psz_string, (*psz_string) ? "%s:%s" : "%s%s",
779                             psz_string, psz_name );
780             free( psz_parser );
781         }
782         else
783             return;
784     }
785     else
786     {
787         if( psz_parser )
788         {
789             memmove( psz_parser, psz_parser + strlen(psz_name) +
790                             (*(psz_parser + strlen(psz_name)) == ':' ? 1 : 0 ),
791                             strlen(psz_parser + strlen(psz_name)) + 1 );
792
793             /* Remove trailing : : */
794             if( *(psz_string+strlen(psz_string ) -1 ) == ':' )
795             {
796                 *(psz_string+strlen(psz_string ) -1 ) = '\0';
797             }
798          }
799          else
800          {
801              free( psz_string );
802              return;
803          }
804     }
805     if( b_setconfig )
806         config_PutPsz( p_vout, "vout-filter", psz_string );
807
808     var_SetString( p_vout, "vout-filter", psz_string );
809     free( psz_string );
810 }
811
812 /*****************************************************************************
813  * vout_ControlDefault: default methods for video output control.
814  *****************************************************************************/
815 int vout_vaControlDefault( vout_thread_t *p_vout, int i_query, va_list args )
816 {
817     (void)args;
818     switch( i_query )
819     {
820     case VOUT_REPARENT:
821     case VOUT_CLOSE:
822         if( p_vout->p_parent_intf )
823         {
824             vlc_object_release( p_vout->p_parent_intf );
825             p_vout->p_parent_intf = NULL;
826         }
827         return VLC_SUCCESS;
828         break;
829
830     case VOUT_SNAPSHOT:
831         p_vout->b_snapshot = VLC_TRUE;
832         return VLC_SUCCESS;
833         break;
834
835     default:
836         msg_Dbg( p_vout, "control query not supported" );
837         return VLC_EGENERIC;
838     }
839 }
840
841 /*****************************************************************************
842  * InitWindowSize: find the initial dimensions the video window should have.
843  *****************************************************************************
844  * This function will check the "width", "height" and "zoom" config options and
845  * will calculate the size that the video window should have.
846  *****************************************************************************/
847 static void InitWindowSize( vout_thread_t *p_vout, unsigned *pi_width,
848                             unsigned *pi_height )
849 {
850     vlc_value_t val;
851     int i_width, i_height;
852     uint64_t ll_zoom;
853
854 #define FP_FACTOR 1000                             /* our fixed point factor */
855
856     var_Get( p_vout, "width", &val );
857     i_width = val.i_int;
858     var_Get( p_vout, "height", &val );
859     i_height = val.i_int;
860     var_Get( p_vout, "zoom", &val );
861     ll_zoom = (uint64_t)( FP_FACTOR * val.f_float );
862
863     if( i_width > 0 && i_height > 0)
864     {
865         *pi_width = (int)( i_width * ll_zoom / FP_FACTOR );
866         *pi_height = (int)( i_height * ll_zoom / FP_FACTOR );
867         goto initwsize_end;
868     }
869     else if( i_width > 0 )
870     {
871         *pi_width = (int)( i_width * ll_zoom / FP_FACTOR );
872         *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom *
873             p_vout->fmt_in.i_sar_den * i_width / p_vout->fmt_in.i_sar_num /
874             FP_FACTOR / p_vout->fmt_in.i_visible_width );
875         goto initwsize_end;
876     }
877     else if( i_height > 0 )
878     {
879         *pi_height = (int)( i_height * ll_zoom / FP_FACTOR );
880         *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom *
881             p_vout->fmt_in.i_sar_num * i_height / p_vout->fmt_in.i_sar_den /
882             FP_FACTOR / p_vout->fmt_in.i_visible_height );
883         goto initwsize_end;
884     }
885
886     if( p_vout->fmt_in.i_sar_num == 0 || p_vout->fmt_in.i_sar_den == 0 ) {
887         msg_Warn( p_vout, "fucked up aspect" );
888         *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom / FP_FACTOR );
889         *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom /FP_FACTOR);
890     }
891     else if( p_vout->fmt_in.i_sar_num >= p_vout->fmt_in.i_sar_den )
892     {
893         *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom *
894             p_vout->fmt_in.i_sar_num / p_vout->fmt_in.i_sar_den / FP_FACTOR );
895         *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom 
896             / FP_FACTOR );
897     }
898     else
899     {
900         *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom 
901             / FP_FACTOR );
902         *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom *
903             p_vout->fmt_in.i_sar_den / p_vout->fmt_in.i_sar_num / FP_FACTOR );
904     }
905
906 initwsize_end:
907     msg_Dbg( p_vout, "window size: %dx%d", p_vout->i_window_width, 
908              p_vout->i_window_height );
909
910 #undef FP_FACTOR
911 }
912
913 /*****************************************************************************
914  * Object variables callbacks
915  *****************************************************************************/
916 static int ZoomCallback( vlc_object_t *p_this, char const *psz_cmd,
917                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
918 {
919     vout_thread_t *p_vout = (vout_thread_t *)p_this;
920     (void)psz_cmd; (void)oldval; (void)newval; (void)p_data;
921     InitWindowSize( p_vout, &p_vout->i_window_width,
922                     &p_vout->i_window_height );
923     vout_Control( p_vout, VOUT_SET_SIZE, p_vout->i_window_width,
924                   p_vout->i_window_height );
925     return VLC_SUCCESS;
926 }
927
928 static int CropCallback( vlc_object_t *p_this, char const *psz_cmd,
929                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
930 {
931     vout_thread_t *p_vout = (vout_thread_t *)p_this;
932     int64_t i_aspect_num, i_aspect_den;
933     unsigned int i_width, i_height;
934
935     (void)oldval; (void)p_data;
936
937     /* Restore defaults */
938     p_vout->fmt_in.i_x_offset = p_vout->fmt_render.i_x_offset;
939     p_vout->fmt_in.i_visible_width = p_vout->fmt_render.i_visible_width;
940     p_vout->fmt_in.i_y_offset = p_vout->fmt_render.i_y_offset;
941     p_vout->fmt_in.i_visible_height = p_vout->fmt_render.i_visible_height;
942
943     if( !strcmp( psz_cmd, "crop" ) )
944     {
945         char *psz_end = NULL, *psz_parser = strchr( newval.psz_string, ':' );
946         if( psz_parser )
947         {
948             /* We're using the 3:4 syntax */
949             i_aspect_num = strtol( newval.psz_string, &psz_end, 10 );
950             if( psz_end == newval.psz_string || !i_aspect_num ) goto crop_end;
951
952             i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
953             if( psz_end == psz_parser || !i_aspect_den ) goto crop_end;
954
955             i_width = p_vout->fmt_in.i_sar_den*p_vout->fmt_render.i_visible_height *
956                 i_aspect_num / i_aspect_den / p_vout->fmt_in.i_sar_num;
957             i_height = p_vout->fmt_render.i_visible_width*p_vout->fmt_in.i_sar_num *
958                 i_aspect_den / i_aspect_num / p_vout->fmt_in.i_sar_den;
959
960             if( i_width < p_vout->fmt_render.i_visible_width )
961             {
962                 p_vout->fmt_in.i_x_offset = p_vout->fmt_render.i_x_offset +
963                     (p_vout->fmt_render.i_visible_width - i_width) / 2;
964                 p_vout->fmt_in.i_visible_width = i_width;
965             }
966             else
967             {
968                 p_vout->fmt_in.i_y_offset = p_vout->fmt_render.i_y_offset +
969                     (p_vout->fmt_render.i_visible_height - i_height) / 2;
970                 p_vout->fmt_in.i_visible_height = i_height;
971             }
972         }
973         else
974         {
975             psz_parser = strchr( newval.psz_string, 'x' );
976             if( psz_parser )
977             {
978                 /* Maybe we're using the <width>x<height>+<left>+<top> syntax */
979                 unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
980
981                 i_crop_width = strtol( newval.psz_string, &psz_end, 10 );
982                 if( psz_end != psz_parser ) goto crop_end;
983
984                 psz_parser = strchr( ++psz_end, '+' );
985                 i_crop_height = strtol( psz_end, &psz_end, 10 );
986                 if( psz_end != psz_parser ) goto crop_end;
987
988                 psz_parser = strchr( ++psz_end, '+' );
989                 i_crop_left = strtol( psz_end, &psz_end, 10 );
990                 if( psz_end != psz_parser ) goto crop_end;
991
992                 psz_end++;
993                 i_crop_top = strtol( psz_end, &psz_end, 10 );
994                 if( *psz_end != '\0' ) goto crop_end;
995
996                 i_width = i_crop_width;
997                 p_vout->fmt_in.i_visible_width = i_width;
998
999                 i_height = i_crop_height;
1000                 p_vout->fmt_in.i_visible_height = i_height;
1001
1002                 p_vout->fmt_in.i_x_offset = i_crop_left;
1003                 p_vout->fmt_in.i_y_offset = i_crop_top;
1004             }
1005             else
1006             {
1007                 /* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
1008                 unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
1009
1010                 psz_parser = strchr( newval.psz_string, '+' );
1011                 i_crop_left = strtol( newval.psz_string, &psz_end, 10 );
1012                 if( psz_end != psz_parser ) goto crop_end;
1013
1014                 psz_parser = strchr( ++psz_end, '+' );
1015                 i_crop_top = strtol( psz_end, &psz_end, 10 );
1016                 if( psz_end != psz_parser ) goto crop_end;
1017
1018                 psz_parser = strchr( ++psz_end, '+' );
1019                 i_crop_right = strtol( psz_end, &psz_end, 10 );
1020                 if( psz_end != psz_parser ) goto crop_end;
1021
1022                 psz_end++;
1023                 i_crop_bottom = strtol( psz_end, &psz_end, 10 );
1024                 if( *psz_end != '\0' ) goto crop_end;
1025
1026                 i_width = p_vout->fmt_render.i_visible_width
1027                           - i_crop_left - i_crop_right;
1028                 p_vout->fmt_in.i_visible_width = i_width;
1029
1030                 i_height = p_vout->fmt_render.i_visible_height
1031                            - i_crop_top - i_crop_bottom;
1032                 p_vout->fmt_in.i_visible_height = i_height;
1033
1034                 p_vout->fmt_in.i_x_offset = i_crop_left;
1035                 p_vout->fmt_in.i_y_offset = i_crop_top;
1036             }
1037         }
1038     }
1039     else if( !strcmp( psz_cmd, "crop-top" )
1040           || !strcmp( psz_cmd, "crop-left" )
1041           || !strcmp( psz_cmd, "crop-bottom" )
1042           || !strcmp( psz_cmd, "crop-right" ) )
1043     {
1044         unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
1045
1046         i_crop_top = var_GetInteger( p_vout, "crop-top" );
1047         i_crop_left = var_GetInteger( p_vout, "crop-left" );
1048         i_crop_right = var_GetInteger( p_vout, "crop-right" );
1049         i_crop_bottom = var_GetInteger( p_vout, "crop-bottom" );
1050
1051         i_width = p_vout->fmt_render.i_visible_width
1052                   - i_crop_left - i_crop_right;
1053         p_vout->fmt_in.i_visible_width = i_width;
1054
1055         i_height = p_vout->fmt_render.i_visible_height
1056                    - i_crop_top - i_crop_bottom;
1057         p_vout->fmt_in.i_visible_height = i_height;
1058
1059         p_vout->fmt_in.i_x_offset = i_crop_left;
1060         p_vout->fmt_in.i_y_offset = i_crop_top;
1061     }
1062
1063  crop_end:
1064     InitWindowSize( p_vout, &p_vout->i_window_width,
1065                     &p_vout->i_window_height );
1066
1067     p_vout->i_changes |= VOUT_CROP_CHANGE;
1068
1069     msg_Dbg( p_vout, "cropping picture %ix%i to %i,%i,%ix%i",
1070              p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
1071              p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
1072              p_vout->fmt_in.i_visible_width,
1073              p_vout->fmt_in.i_visible_height );
1074
1075     return VLC_SUCCESS;
1076 }
1077
1078 static int AspectCallback( vlc_object_t *p_this, char const *psz_cmd,
1079                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
1080 {
1081     vout_thread_t *p_vout = (vout_thread_t *)p_this;
1082     unsigned int i_aspect_num, i_aspect_den, i_sar_num, i_sar_den;
1083     vlc_value_t val;
1084
1085     char *psz_end, *psz_parser = strchr( newval.psz_string, ':' );
1086     (void)psz_cmd; (void)oldval; (void)p_data;
1087
1088     /* Restore defaults */
1089     p_vout->fmt_in.i_sar_num = p_vout->fmt_render.i_sar_num;
1090     p_vout->fmt_in.i_sar_den = p_vout->fmt_render.i_sar_den;
1091     p_vout->fmt_in.i_aspect = p_vout->fmt_render.i_aspect;
1092     p_vout->render.i_aspect = p_vout->fmt_render.i_aspect;
1093
1094     if( !psz_parser ) goto aspect_end;
1095
1096     i_aspect_num = strtol( newval.psz_string, &psz_end, 10 );
1097     if( psz_end == newval.psz_string || !i_aspect_num ) goto aspect_end;
1098
1099     i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
1100     if( psz_end == psz_parser || !i_aspect_den ) goto aspect_end;
1101
1102     i_sar_num = i_aspect_num * p_vout->fmt_render.i_visible_height;
1103     i_sar_den = i_aspect_den * p_vout->fmt_render.i_visible_width;
1104     vlc_ureduce( &i_sar_num, &i_sar_den, i_sar_num, i_sar_den, 0 );
1105     p_vout->fmt_in.i_sar_num = i_sar_num;
1106     p_vout->fmt_in.i_sar_den = i_sar_den;
1107     p_vout->fmt_in.i_aspect = i_aspect_num * VOUT_ASPECT_FACTOR / i_aspect_den;
1108     p_vout->render.i_aspect = p_vout->fmt_in.i_aspect;
1109
1110  aspect_end:
1111     if( p_vout->i_par_num && p_vout->i_par_den )
1112     {
1113         p_vout->fmt_in.i_sar_num *= p_vout->i_par_den;
1114         p_vout->fmt_in.i_sar_den *= p_vout->i_par_num;
1115         p_vout->fmt_in.i_aspect = p_vout->fmt_in.i_aspect *
1116             p_vout->i_par_den / p_vout->i_par_num;
1117         p_vout->render.i_aspect = p_vout->fmt_in.i_aspect;
1118     }
1119
1120     p_vout->i_changes |= VOUT_ASPECT_CHANGE;
1121
1122     vlc_ureduce( &i_aspect_num, &i_aspect_den,
1123                  p_vout->fmt_in.i_aspect, VOUT_ASPECT_FACTOR, 0 );
1124     msg_Dbg( p_vout, "new aspect-ratio %i:%i, sample aspect-ratio %i:%i",
1125              i_aspect_num, i_aspect_den,
1126              p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den );
1127
1128     var_Get( p_vout, "crop", &val );
1129     return CropCallback( p_this, "crop", val, val, 0 );
1130
1131     return VLC_SUCCESS;
1132 }
1133
1134 static int OnTopCallback( vlc_object_t *p_this, char const *psz_cmd,
1135                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
1136 {
1137     vout_thread_t *p_vout = (vout_thread_t *)p_this;
1138     playlist_t *p_playlist = pl_Yield( p_this );
1139     vout_Control( p_vout, VOUT_SET_STAY_ON_TOP, newval.b_bool );
1140     (void)psz_cmd; (void)oldval; (void)p_data;
1141
1142     /* Modify playlist as well because the vout might have to be restarted */
1143     var_Create( p_playlist, "video-on-top", VLC_VAR_BOOL );
1144     var_Set( p_playlist, "video-on-top", newval );
1145
1146     pl_Release( p_this );
1147     return VLC_SUCCESS;
1148 }
1149
1150 static int FullscreenCallback( vlc_object_t *p_this, char const *psz_cmd,
1151                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
1152 {
1153     vout_thread_t *p_vout = (vout_thread_t *)p_this;
1154     vlc_value_t val;
1155     playlist_t *p_playlist = pl_Yield( p_this );
1156     (void)psz_cmd; (void)oldval; (void)p_data;
1157
1158     p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
1159
1160     /* Modify playlist as well because the vout might have to be restarted */
1161     var_Create( p_playlist, "fullscreen", VLC_VAR_BOOL );
1162     var_Set( p_playlist, "fullscreen", newval );
1163     pl_Release( p_playlist );
1164
1165     /* Disable "always on top" in fullscreen mode */
1166     var_Get( p_vout, "video-on-top", &val );
1167     if( val.b_bool )
1168         vout_Control( p_vout, VOUT_SET_STAY_ON_TOP,
1169                       (vlc_bool_t)!newval.b_bool );
1170
1171     val.b_bool = VLC_TRUE;
1172     var_Set( p_vout, "intf-change", val );
1173     return VLC_SUCCESS;
1174 }
1175
1176 static int SnapshotCallback( vlc_object_t *p_this, char const *psz_cmd,
1177                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
1178 {
1179     vout_thread_t *p_vout = (vout_thread_t *)p_this;
1180     vout_Control( p_vout, VOUT_SNAPSHOT );
1181     (void)psz_cmd; (void)oldval; (void)newval; (void)p_data;
1182     return VLC_SUCCESS;
1183 }
1184
1185 static int TitleCallback( vlc_object_t *p_this, char const *psz_cmd,
1186                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
1187 {
1188     vout_thread_t *p_vout = (vout_thread_t *)p_this;
1189
1190     if( !strncmp( psz_cmd, "video-title-show", 16 ) )
1191         p_vout->b_title_show = newval.b_bool;
1192     else if( !strncmp( psz_cmd, "video-title-timeout", 19 ) )
1193         p_vout->i_title_timeout = (mtime_t) newval.i_int;
1194     else if( !strncmp( psz_cmd, "video-title-position", 20 ) )
1195         p_vout->i_title_position = newval.i_int;
1196 }