vout_intf.c 38.6 KB
Newer Older
gbazin's avatar
gbazin committed
1
2
3
/*****************************************************************************
 * vout_intf.c : video output interface
 *****************************************************************************
4
 * Copyright (C) 2000-2006 the VideoLAN team
5
 * $Id$
gbazin's avatar
gbazin committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 *
 * Authors: Gildas Bazin <gbazin@videolan.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
gbazin's avatar
gbazin committed
22
23
24
25
26
27
28
29
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                                /* free() */

#include <vlc/vlc.h>
30
#include <vlc/intf.h>
31
#include <vlc_block.h>
gbazin's avatar
gbazin committed
32
33
34

#include "vlc_video.h"
#include "video_output.h"
35
36
#include "vlc_image.h"
#include "vlc_spu.h"
37

38
39
#include <snapshot.h>

gbazin's avatar
gbazin committed
40
41
42
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
43
static void InitWindowSize( vout_thread_t *, unsigned *, unsigned * );
gbazin's avatar
gbazin committed
44

45
46
47
/* Object variables callbacks */
static int ZoomCallback( vlc_object_t *, char const *,
                         vlc_value_t, vlc_value_t, void * );
48
49
static int CropCallback( vlc_object_t *, char const *,
                         vlc_value_t, vlc_value_t, void * );
50
51
static int AspectCallback( vlc_object_t *, char const *,
                           vlc_value_t, vlc_value_t, void * );
52
53
static int OnTopCallback( vlc_object_t *, char const *,
                          vlc_value_t, vlc_value_t, void * );
54
55
static int FullscreenCallback( vlc_object_t *, char const *,
                               vlc_value_t, vlc_value_t, void * );
56
57
static int SnapshotCallback( vlc_object_t *, char const *,
                             vlc_value_t, vlc_value_t, void * );
58

gbazin's avatar
gbazin committed
59
60
61
62
63
64
65
66
67
68
69
70
/*****************************************************************************
 * vout_RequestWindow: Create/Get a video window if possible.
 *****************************************************************************
 * This function looks for the main interface and tries to request
 * a new video window. If it fails then the vout will still need to create the
 * window by itself.
 *****************************************************************************/
void *vout_RequestWindow( vout_thread_t *p_vout,
                          int *pi_x_hint, int *pi_y_hint,
                          unsigned int *pi_width_hint,
                          unsigned int *pi_height_hint )
{
71
72
    intf_thread_t *p_intf = NULL;
    vlc_list_t *p_list;
gbazin's avatar
gbazin committed
73
74
    void *p_window;
    vlc_value_t val;
75
    int i;
gbazin's avatar
gbazin committed
76

77
78
79
    /* Small kludge */
    if( !var_Type( p_vout, "aspect-ratio" ) ) vout_IntfInit( p_vout );

gbazin's avatar
gbazin committed
80
81
82
83
84
85
86
87
88
89
90
91
92
    /* Get requested coordinates */
    var_Get( p_vout, "video-x", &val );
    *pi_x_hint = val.i_int ;
    var_Get( p_vout, "video-y", &val );
    *pi_y_hint = val.i_int;

    *pi_width_hint = p_vout->i_window_width;
    *pi_height_hint = p_vout->i_window_height;

    /* Check whether someone provided us with a window ID */
    var_Get( p_vout->p_vlc, "drawable", &val );
    if( val.i_int ) return (void *)val.i_int;

93
    /* Find if the main interface supports embedding */
94
95
    p_list = vlc_list_find( p_vout, VLC_OBJECT_INTF, FIND_ANYWHERE );
    if( !p_list ) return NULL;
gbazin's avatar
gbazin committed
96

97
    for( i = 0; i < p_list->i_count; i++ )
gbazin's avatar
gbazin committed
98
    {
99
        p_intf = (intf_thread_t *)p_list->p_values[i].p_object;
100
        if( p_intf->b_block && p_intf->pf_request_window ) break;
101
102
103
104
105
106
        p_intf = NULL;
    }

    if( !p_intf )
    {
        vlc_list_release( p_list );
gbazin's avatar
gbazin committed
107
108
109
        return NULL;
    }

110
111
112
    vlc_object_yield( p_intf );
    vlc_list_release( p_list );

113
    p_window = p_intf->pf_request_window( p_intf, p_vout, pi_x_hint, pi_y_hint,
gbazin's avatar
gbazin committed
114
                                          pi_width_hint, pi_height_hint );
115
116
117

    if( !p_window ) vlc_object_release( p_intf );
    else p_vout->p_parent_intf = p_intf;
gbazin's avatar
gbazin committed
118
119
120
121
122
123

    return p_window;
}

void vout_ReleaseWindow( vout_thread_t *p_vout, void *p_window )
{
124
    intf_thread_t *p_intf = p_vout->p_parent_intf;
gbazin's avatar
gbazin committed
125
126
127

    if( !p_intf ) return;

128
129
130
131
132
133
134
    vlc_mutex_lock( &p_intf->object_lock );
    if( p_intf->b_dead )
    {
        vlc_mutex_unlock( &p_intf->object_lock );
        return;
    }

gbazin's avatar
gbazin committed
135
136
137
    if( !p_intf->pf_release_window )
    {
        msg_Err( p_vout, "no pf_release_window");
138
        vlc_mutex_unlock( &p_intf->object_lock );
gbazin's avatar
gbazin committed
139
140
141
142
143
        vlc_object_release( p_intf );
        return;
    }

    p_intf->pf_release_window( p_intf, p_window );
144
145
146

    p_vout->p_parent_intf = NULL;
    vlc_mutex_unlock( &p_intf->object_lock );
gbazin's avatar
gbazin committed
147
148
    vlc_object_release( p_intf );
}
149

150
151
152
int vout_ControlWindow( vout_thread_t *p_vout, void *p_window,
                        int i_query, va_list args )
{
153
    intf_thread_t *p_intf = p_vout->p_parent_intf;
154
155
156
157
    int i_ret;

    if( !p_intf ) return VLC_EGENERIC;

158
159
160
161
162
163
164
    vlc_mutex_lock( &p_intf->object_lock );
    if( p_intf->b_dead )
    {
        vlc_mutex_unlock( &p_intf->object_lock );
        return VLC_EGENERIC;
    }

165
166
167
    if( !p_intf->pf_control_window )
    {
        msg_Err( p_vout, "no pf_control_window");
168
        vlc_mutex_unlock( &p_intf->object_lock );
169
170
171
172
        return VLC_EGENERIC;
    }

    i_ret = p_intf->pf_control_window( p_intf, p_window, i_query, args );
173
    vlc_mutex_unlock( &p_intf->object_lock );
174
175
176
    return i_ret;
}

177
178
179
180
181
182
/*****************************************************************************
 * vout_IntfInit: called during the vout creation to initialise misc things.
 *****************************************************************************/
void vout_IntfInit( vout_thread_t *p_vout )
{
    vlc_value_t val, text, old_val;
183
    vlc_bool_t b_force_par = VLC_FALSE;
184
    char *psz_buf;
185
186

    /* Create a few object variables we'll need later on */
187
    var_Create( p_vout, "snapshot-path", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
188
    var_Create( p_vout, "snapshot-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
189
    var_Create( p_vout, "snapshot-preview", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
190
191
192
    var_Create( p_vout, "width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_vout, "height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_vout, "align", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
193
194
195
    var_Get( p_vout, "align", &val );
    p_vout->i_alignment = val.i_int;

196
197
198
    var_Create( p_vout, "video-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_vout, "video-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );

199
    /* Zoom object var */
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    var_Create( p_vout, "zoom", VLC_VAR_FLOAT | VLC_VAR_ISCOMMAND |
                VLC_VAR_HASCHOICE | VLC_VAR_DOINHERIT );

    text.psz_string = _("Zoom");
    var_Change( p_vout, "zoom", VLC_VAR_SETTEXT, &text, NULL );

    var_Get( p_vout, "zoom", &old_val );
    if( old_val.f_float == 0.25 ||
        old_val.f_float == 0.5 ||
        old_val.f_float == 1 ||
        old_val.f_float == 2 )
    {
        var_Change( p_vout, "zoom", VLC_VAR_DELCHOICE, &old_val, NULL );
    }

Felix Paul Kühne's avatar
Felix Paul Kühne committed
215
    val.f_float = 0.25; text.psz_string = _("1:4 Quarter");
216
217
218
219
220
221
222
223
224
225
226
    var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, &val, &text );
    val.f_float = 0.5; text.psz_string = _("1:2 Half");
    var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, &val, &text );
    val.f_float = 1; text.psz_string = _("1:1 Original");
    var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, &val, &text );
    val.f_float = 2; text.psz_string = _("2:1 Double");
    var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, &val, &text );

    var_Set( p_vout, "zoom", old_val );

    var_AddCallback( p_vout, "zoom", ZoomCallback, NULL );
227

228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
    /* Crop offset vars */
    var_Create( p_vout, "crop-left", VLC_VAR_INTEGER );
    var_Create( p_vout, "crop-top", VLC_VAR_INTEGER );
    var_Create( p_vout, "crop-right", VLC_VAR_INTEGER );
    var_Create( p_vout, "crop-bottom", VLC_VAR_INTEGER );

    var_SetInteger( p_vout, "crop-left", 0 );
    var_SetInteger( p_vout, "crop-top", 0 );
    var_SetInteger( p_vout, "crop-right", 0 );
    var_SetInteger( p_vout, "crop-bottom", 0 );

    var_AddCallback( p_vout, "crop-left", CropCallback, NULL );
    var_AddCallback( p_vout, "crop-top", CropCallback, NULL );
    var_AddCallback( p_vout, "crop-right", CropCallback, NULL );
    var_AddCallback( p_vout, "crop-bottom", CropCallback, NULL );

244
245
    /* Crop object var */
    var_Create( p_vout, "crop", VLC_VAR_STRING |
246
247
248
249
250
251
252
253
254
                VLC_VAR_HASCHOICE | VLC_VAR_DOINHERIT );

    text.psz_string = _("Crop");
    var_Change( p_vout, "crop", VLC_VAR_SETTEXT, &text, NULL );

    val.psz_string = "";
    var_Change( p_vout, "crop", VLC_VAR_DELCHOICE, &val, 0 );
    val.psz_string = ""; text.psz_string = _("Default");
    var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
255
    val.psz_string = "1:1"; text.psz_string = "1:1";
256
    var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
257
    val.psz_string = "4:3"; text.psz_string = "4:3";
258
    var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
259
    val.psz_string = "16:9"; text.psz_string = "16:9";
260
    var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
261
    val.psz_string = "16:10"; text.psz_string = "16:10";
262
    var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
Marian Durkovic's avatar
Marian Durkovic committed
263
    val.psz_string = "221:100"; text.psz_string = "221:100";
264
    var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
265
266
    val.psz_string = "5:4"; text.psz_string = "5:4";
    var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
267

268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
    /* Add custom crop ratios */
    psz_buf = config_GetPsz( p_vout, "custom-crop-ratios" );
    if( psz_buf && *psz_buf )
    {
        char *psz_cur = psz_buf;
        char *psz_next;
        while( psz_cur && *psz_cur )
        {
            psz_next = strchr( psz_cur, ',' );
            if( psz_next )
            {
                *psz_next = '\0';
                psz_next++;
            }
            val.psz_string = strdup( psz_cur );
            text.psz_string = strdup( psz_cur );
            var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text);
            free( val.psz_string );
            free( text.psz_string );
            psz_cur = psz_next;
        }
    }
    if( psz_buf ) free( psz_buf );

292
    var_AddCallback( p_vout, "crop", CropCallback, NULL );
293
294
295
296
297
298
    var_Get( p_vout, "crop", &old_val );
    if( old_val.psz_string && *old_val.psz_string )
        var_Change( p_vout, "crop", VLC_VAR_TRIGGER_CALLBACKS, 0, 0 );
    if( old_val.psz_string ) free( old_val.psz_string );

    /* Monitor pixel aspect-ratio */
299
300
301
    var_Create( p_vout, "monitor-par", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Get( p_vout, "monitor-par", &val );
    if( val.psz_string && *val.psz_string )
302
303
304
305
306
307
    {
        char *psz_parser = strchr( val.psz_string, ':' );
        unsigned int i_aspect_num = 0, i_aspect_den = 0;
        float i_aspect = 0;
        if( psz_parser )
        {
308
309
            i_aspect_num = strtol( val.psz_string, 0, 10 );
            i_aspect_den = strtol( ++psz_parser, 0, 10 );
310
311
312
313
314
315
316
        }
        else
        {
            i_aspect = atof( val.psz_string );
            vlc_ureduce( &i_aspect_num, &i_aspect_den,
                         i_aspect *VOUT_ASPECT_FACTOR, VOUT_ASPECT_FACTOR, 0 );
        }
317
318
319
        if( !i_aspect_num || !i_aspect_den ) i_aspect_num = i_aspect_den = 1;

        p_vout->i_par_num = i_aspect_num;
320
321
322
323
        p_vout->i_par_den = i_aspect_den;

        vlc_ureduce( &p_vout->i_par_num, &p_vout->i_par_den,
                     p_vout->i_par_num, p_vout->i_par_den, 0 );
324

325
        msg_Dbg( p_vout, "overriding monitor pixel aspect-ratio: %i:%i",
326
327
                 p_vout->i_par_num, p_vout->i_par_den );
        b_force_par = VLC_TRUE;
328
    }
329
    if( val.psz_string ) free( val.psz_string );
330
331
332
333
334
335
336
337
338
339
340
341

    /* Aspect-ratio object var */
    var_Create( p_vout, "aspect-ratio", VLC_VAR_STRING |
                VLC_VAR_HASCHOICE | VLC_VAR_DOINHERIT );

    text.psz_string = _("Aspect-ratio");
    var_Change( p_vout, "aspect-ratio", VLC_VAR_SETTEXT, &text, NULL );

    val.psz_string = "";
    var_Change( p_vout, "aspect-ratio", VLC_VAR_DELCHOICE, &val, 0 );
    val.psz_string = ""; text.psz_string = _("Default");
    var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
342
    val.psz_string = "1:1"; text.psz_string = "1:1";
343
    var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
344
    val.psz_string = "4:3"; text.psz_string = "4:3";
345
    var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
346
    val.psz_string = "16:9"; text.psz_string = "16:9";
347
    var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
348
    val.psz_string = "16:10"; text.psz_string = "16:10";
349
    var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
Marian Durkovic's avatar
Marian Durkovic committed
350
    val.psz_string = "221:100"; text.psz_string = "221:100";
351
    var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
352
353
    val.psz_string = "5:4"; text.psz_string = "5:4";
    var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
354

355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
    /* Add custom aspect ratios */
    psz_buf = config_GetPsz( p_vout, "custom-aspect-ratios" );
    if( psz_buf && *psz_buf )
    {
        char *psz_cur = psz_buf;
        char *psz_next;
        while( psz_cur && *psz_cur )
        {
            psz_next = strchr( psz_cur, ',' );
            if( psz_next )
            {
                *psz_next = '\0';
                psz_next++;
            }
            val.psz_string = strdup( psz_cur );
            text.psz_string = strdup( psz_cur );
            var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text);
            free( val.psz_string );
            free( text.psz_string );
            psz_cur = psz_next;
        }
    }
    if( psz_buf ) free( psz_buf );

379
380
    var_AddCallback( p_vout, "aspect-ratio", AspectCallback, NULL );
    var_Get( p_vout, "aspect-ratio", &old_val );
381
    if( (old_val.psz_string && *old_val.psz_string) || b_force_par )
382
383
        var_Change( p_vout, "aspect-ratio", VLC_VAR_TRIGGER_CALLBACKS, 0, 0 );
    if( old_val.psz_string ) free( old_val.psz_string );
384

385
386
387
388
    /* Initialize the dimensions of the video window */
    InitWindowSize( p_vout, &p_vout->i_window_width,
                    &p_vout->i_window_height );

389
390
391
392
393
    /* Add a variable to indicate if the window should be on top of others */
    var_Create( p_vout, "video-on-top", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    text.psz_string = _("Always on top");
    var_Change( p_vout, "video-on-top", VLC_VAR_SETTEXT, &text, NULL );
    var_AddCallback( p_vout, "video-on-top", OnTopCallback, NULL );
394

395
396
397
    /* Add a variable to indicate whether we want window decoration or not */
    var_Create( p_vout, "video-deco", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );

398
399
400
401
402
403
404
405
406
407
408
    /* Add a fullscreen variable */
    var_Create( p_vout, "fullscreen", VLC_VAR_BOOL );
    text.psz_string = _("Fullscreen");
    var_Change( p_vout, "fullscreen", VLC_VAR_SETTEXT, &text, NULL );
    var_Change( p_vout, "fullscreen", VLC_VAR_INHERITVALUE, &val, NULL );
    if( val.b_bool )
    {
        /* user requested fullscreen */
        p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
    }
    var_AddCallback( p_vout, "fullscreen", FullscreenCallback, NULL );
409

410
411
412
413
414
415
    /* Add a snapshot variable */
    var_Create( p_vout, "video-snapshot", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
    text.psz_string = _("Snapshot");
    var_Change( p_vout, "video-snapshot", VLC_VAR_SETTEXT, &text, NULL );
    var_AddCallback( p_vout, "video-snapshot", SnapshotCallback, NULL );

416
417
418
419
420
421
422
    /* Mouse coordinates */
    var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
    var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER );
    var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
    var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL );
    var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER );

423
424
425
    var_Create( p_vout, "intf-change", VLC_VAR_BOOL );
    val.b_bool = VLC_TRUE;
    var_Set( p_vout, "intf-change", val );
426
427
}

428
429
430
431
432
433
434
435
436
437
/*****************************************************************************
 * vout_Snapshot: generates a snapshot.
 *****************************************************************************/
int vout_Snapshot( vout_thread_t *p_vout, picture_t *p_pic )
{
    image_handler_t *p_image = image_HandlerCreate( p_vout );
    video_format_t fmt_in = {0}, fmt_out = {0};
    char *psz_filename;
    subpicture_t *p_subpic;
    picture_t *p_pif;
438
    vlc_value_t val, format;
439
440
441
442
443
444
445
446
    int i_ret;

    var_Get( p_vout, "snapshot-path", &val );
    if( val.psz_string && !*val.psz_string )
    {
        free( val.psz_string );
        val.psz_string = 0;
    }
447

448
449
450
451
452
    /* Embedded snapshot : if snapshot-path == object:object-id, then
       create a snapshot_t* and store it in
       object(object-id)->p_private, then unlock and signal the
       waiting object.
     */
453
    if( val.psz_string && !strncmp( val.psz_string, "object:", 7 ) )
454
455
456
457
458
    {
        int i_id;
        vlc_object_t* p_dest;
        block_t *p_block;
        snapshot_t *p_snapshot;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
459
        int i_size;
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476

        /* Destination object-id is following object: */
        i_id = atoi( &val.psz_string[7] );
        p_dest = ( vlc_object_t* )vlc_current_object( i_id );
        if( !p_dest )
        {
            msg_Err( p_vout, "Cannot find calling object" );
            image_HandlerDelete( p_image );
            return VLC_EGENERIC;
        }
        /* Object must be locked. We will unlock it once we get the
           snapshot and written it to p_private */
        p_dest->p_private = NULL;

        /* Save the snapshot to a memory zone */
        fmt_in = p_vout->fmt_in;
        fmt_out.i_sar_num = fmt_out.i_sar_den = 1;
477
478
        /* FIXME: should not be hardcoded. We should be able to
        specify the snapshot size (snapshot-width and snapshot-height). */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
479
480
481
        fmt_out.i_width = 320;
        fmt_out.i_height = 200;
        fmt_out.i_chroma = VLC_FOURCC( 'p','n','g',' ' );
482
        p_block = ( block_t* ) image_Write( p_image, p_pic, &fmt_in, &fmt_out );
483
        if( !p_block )
484
485
486
487
488
        {
            msg_Err( p_vout, "Could not get snapshot" );
            image_HandlerDelete( p_image );
            vlc_cond_signal( &p_dest->object_wait );
            vlc_mutex_unlock( &p_dest->object_lock );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
489
            vlc_object_release( p_dest );
490
491
492
493
494
495
496
497
498
499
500
501
            return VLC_EGENERIC;
        }

        /* Copy the p_block data to a snapshot structure */
        /* FIXME: get the timestamp */
        p_snapshot = ( snapshot_t* ) malloc( sizeof( snapshot_t ) );
        if( !p_snapshot )
        {
            block_Release( p_block );
            image_HandlerDelete( p_image );
            vlc_cond_signal( &p_dest->object_wait );
            vlc_mutex_unlock( &p_dest->object_lock );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
502
            vlc_object_release( p_dest );
503
504
505
            return VLC_ENOMEM;
        }

Jean-Paul Saman's avatar
Jean-Paul Saman committed
506
        i_size = p_block->i_buffer;
507
508
509
510
511
512
513
514
515
516
517
518
519

        p_snapshot->i_width = fmt_out.i_width;
        p_snapshot->i_height = fmt_out.i_height;
        p_snapshot->i_datasize = i_size;
        p_snapshot->date = p_block->i_pts; /* FIXME ?? */
        p_snapshot->p_data = ( char* ) malloc( i_size );
        if( !p_snapshot->p_data )
        {
            block_Release( p_block );
            free( p_snapshot );
            image_HandlerDelete( p_image );
            vlc_cond_signal( &p_dest->object_wait );
            vlc_mutex_unlock( &p_dest->object_lock );
520
            vlc_object_release( p_dest );
521
522
            return VLC_ENOMEM;
        }
523
        memcpy( p_snapshot->p_data, p_block->p_buffer, p_block->i_buffer );
524

525
        p_dest->p_private = p_snapshot;
526
527

        block_Release( p_block );
528

529
530
531
        /* Unlock the object */
        vlc_cond_signal( &p_dest->object_wait );
        vlc_mutex_unlock( &p_dest->object_lock );
532
        vlc_object_release( p_dest );
533
534

        image_HandlerDelete( p_image );
535
        return VLC_SUCCESS;
536
537
    }

538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622

#if defined(__APPLE__) || defined(SYS_BEOS)
    if( !val.psz_string && p_vout->p_vlc->psz_homedir )
    {
        asprintf( &val.psz_string, "%s/Desktop",
                  p_vout->p_vlc->psz_homedir );
    }

#elif defined(WIN32) && !defined(UNDER_CE)
    if( !val.psz_string && p_vout->p_vlc->psz_homedir )
    {
        /* Get the My Pictures folder path */

        char *p_mypicturesdir = NULL;
        typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD,
                                                   LPSTR );
        #ifndef CSIDL_FLAG_CREATE
        #   define CSIDL_FLAG_CREATE 0x8000
        #endif
        #ifndef CSIDL_MYPICTURES
        #   define CSIDL_MYPICTURES 0x27
        #endif
        #ifndef SHGFP_TYPE_CURRENT
        #   define SHGFP_TYPE_CURRENT 0
        #endif

        HINSTANCE shfolder_dll;
        SHGETFOLDERPATH SHGetFolderPath ;

        /* load the shfolder dll to retrieve SHGetFolderPath */
        if( ( shfolder_dll = LoadLibrary( _T("SHFolder.dll") ) ) != NULL )
        {
            SHGetFolderPath = (void *)GetProcAddress( shfolder_dll,
                                                      _T("SHGetFolderPathA") );
            if( SHGetFolderPath != NULL )
            {
                p_mypicturesdir = (char *)malloc( MAX_PATH );
                if( p_mypicturesdir ) 
                {

                    if( S_OK != SHGetFolderPath( NULL,
                                        CSIDL_MYPICTURES | CSIDL_FLAG_CREATE,
                                        NULL, SHGFP_TYPE_CURRENT,
                                        p_mypicturesdir ) )
                    {
                        free( p_mypicturesdir );
                        p_mypicturesdir = NULL;
                    }
                }
            }
            FreeLibrary( shfolder_dll );
        }

        if( p_mypicturesdir == NULL )
        {
            asprintf( &val.psz_string, "%s/" CONFIG_DIR,
                      p_vout->p_vlc->psz_homedir );
        }
        else
        {
            asprintf( &val.psz_string, p_mypicturesdir );
            free( p_mypicturesdir );
        }
    }

#else
    if( !val.psz_string && p_vout->p_vlc->psz_homedir )
    {
        asprintf( &val.psz_string, "%s/" CONFIG_DIR,
                  p_vout->p_vlc->psz_homedir );
    }
#endif

    if( !val.psz_string )
    {
        msg_Err( p_vout, "no directory specified for snapshots" );
        return VLC_EGENERIC;
    }
    var_Get( p_vout, "snapshot-format", &format );
    if( !format.psz_string || !*format.psz_string )
    {
        if( format.psz_string ) free( format.psz_string );
        format.psz_string = strdup( "png" );
    }

623
    asprintf( &psz_filename, "%s/vlcsnap-%u.%s", val.psz_string,
624
625
              (unsigned int)(p_pic->date / 100000) & 0xFFFFFF,
              format.psz_string );
626
    free( val.psz_string );
627
    free( format.psz_string );
628
629

    /* Save the snapshot */
630
    fmt_in = p_vout->fmt_in;
631
    fmt_out.i_sar_num = fmt_out.i_sar_den = 1;
632
633
634
635
636
637
638
639
640
641
    i_ret = image_WriteUrl( p_image, p_pic, &fmt_in, &fmt_out, psz_filename );
    if( i_ret != VLC_SUCCESS )
    {
        msg_Err( p_vout, "could not create snapshot %s", psz_filename );
        free( psz_filename );
        image_HandlerDelete( p_image );
        return VLC_EGENERIC;
    }

    msg_Dbg( p_vout, "snapshot taken (%s)", psz_filename );
642
    vout_OSDMessage( VLC_OBJECT( p_vout ), DEFAULT_CHAN,
643
                     "%s", psz_filename );
644
645
    free( psz_filename );

646
    if( var_GetBool( p_vout, "snapshot-preview" ) )
647
    {
648
649
650
651
652
653
654
655
656
657
658
659
660
        /* Inject a subpicture with the snapshot */
        memset( &fmt_out, 0, sizeof(fmt_out) );
        fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
        p_pif = image_Convert( p_image, p_pic, &fmt_in, &fmt_out );
        image_HandlerDelete( p_image );
        if( !p_pif ) return VLC_EGENERIC;

        p_subpic = spu_CreateSubpicture( p_vout->p_spu );
        if( p_subpic == NULL )
        {
             p_pif->pf_release( p_pif );
             return VLC_EGENERIC;
        }
661

662
663
664
665
666
667
668
        p_subpic->i_channel = 0;
        p_subpic->i_start = mdate();
        p_subpic->i_stop = mdate() + 4000000;
        p_subpic->b_ephemer = VLC_TRUE;
        p_subpic->b_fade = VLC_TRUE;
        p_subpic->i_original_picture_width = p_vout->render.i_width * 4;
        p_subpic->i_original_picture_height = p_vout->render.i_height * 4;
669

670
671
672
673
        p_subpic->p_region = spu_CreateRegion( p_vout->p_spu, &fmt_out );
        vout_CopyPicture( p_image->p_parent, &p_subpic->p_region->picture,
                          p_pif );
        p_pif->pf_release( p_pif );
674

675
676
677
678
679
680
        spu_DisplaySubpicture( p_vout->p_spu, p_subpic );
    }
    else
    {
        image_HandlerDelete( p_image );
    }
681
682
683
684

    return VLC_SUCCESS;
}

685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
/*****************************************************************************
 * vout_ControlDefault: default methods for video output control.
 *****************************************************************************/
int vout_vaControlDefault( vout_thread_t *p_vout, int i_query, va_list args )
{
    switch( i_query )
    {
    case VOUT_REPARENT:
    case VOUT_CLOSE:
        if( p_vout->p_parent_intf )
        {
            vlc_object_release( p_vout->p_parent_intf );
            p_vout->p_parent_intf = NULL;
        }
        return VLC_SUCCESS;
        break;

702
703
704
705
706
    case VOUT_SNAPSHOT:
        p_vout->b_snapshot = VLC_TRUE;
        return VLC_SUCCESS;
        break;

707
708
709
710
711
712
    default:
        msg_Dbg( p_vout, "control query not supported" );
        return VLC_EGENERIC;
    }
}

713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
/*****************************************************************************
 * InitWindowSize: find the initial dimensions the video window should have.
 *****************************************************************************
 * This function will check the "width", "height" and "zoom" config options and
 * will calculate the size that the video window should have.
 *****************************************************************************/
static void InitWindowSize( vout_thread_t *p_vout, unsigned *pi_width,
                            unsigned *pi_height )
{
    vlc_value_t val;
    int i_width, i_height;
    uint64_t ll_zoom;

#define FP_FACTOR 1000                             /* our fixed point factor */

    var_Get( p_vout, "width", &val );
    i_width = val.i_int;
    var_Get( p_vout, "height", &val );
    i_height = val.i_int;
    var_Get( p_vout, "zoom", &val );
    ll_zoom = (uint64_t)( FP_FACTOR * val.f_float );

    if( i_width > 0 && i_height > 0)
    {
        *pi_width = (int)( i_width * ll_zoom / FP_FACTOR );
        *pi_height = (int)( i_height * ll_zoom / FP_FACTOR );
739
        goto initwsize_end;
740
741
742
743
744
745
746
    }
    else if( i_width > 0 )
    {
        *pi_width = (int)( i_width * ll_zoom / FP_FACTOR );
        *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom *
            p_vout->fmt_in.i_sar_den * i_width / p_vout->fmt_in.i_sar_num /
            FP_FACTOR / p_vout->fmt_in.i_visible_width );
747
        goto initwsize_end;
748
749
750
751
752
753
754
    }
    else if( i_height > 0 )
    {
        *pi_height = (int)( i_height * ll_zoom / FP_FACTOR );
        *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom *
            p_vout->fmt_in.i_sar_num * i_height / p_vout->fmt_in.i_sar_den /
            FP_FACTOR / p_vout->fmt_in.i_visible_height );
755
        goto initwsize_end;
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
    }

    if( p_vout->fmt_in.i_sar_num >= p_vout->fmt_in.i_sar_den )
    {
        *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom *
            p_vout->fmt_in.i_sar_num / p_vout->fmt_in.i_sar_den / FP_FACTOR );
        *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom 
            / FP_FACTOR );
    }
    else
    {
        *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom 
            / FP_FACTOR );
        *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom *
            p_vout->fmt_in.i_sar_den / p_vout->fmt_in.i_sar_num / FP_FACTOR );
    }

773
774
775
776
initwsize_end:
    msg_Dbg( p_vout, "window size: %dx%d", p_vout->i_window_width, 
             p_vout->i_window_height );

777
778
779
#undef FP_FACTOR
}

780
781
782
783
784
785
786
/*****************************************************************************
 * Object variables callbacks
 *****************************************************************************/
static int ZoomCallback( vlc_object_t *p_this, char const *psz_cmd,
                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
787
788
    InitWindowSize( p_vout, &p_vout->i_window_width,
                    &p_vout->i_window_height );
789
    vout_Control( p_vout, VOUT_SET_SIZE, p_vout->i_window_width,
790
                  p_vout->i_window_height );
791
792
    return VLC_SUCCESS;
}
793

794
795
796
797
798
799
800
801
802
803
804
805
806
static int CropCallback( vlc_object_t *p_this, char const *psz_cmd,
                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
    int64_t i_aspect_num, i_aspect_den;
    unsigned int i_width, i_height;

    /* Restore defaults */
    p_vout->fmt_in.i_x_offset = p_vout->fmt_render.i_x_offset;
    p_vout->fmt_in.i_visible_width = p_vout->fmt_render.i_visible_width;
    p_vout->fmt_in.i_y_offset = p_vout->fmt_render.i_y_offset;
    p_vout->fmt_in.i_visible_height = p_vout->fmt_render.i_visible_height;

807
    if( !strcmp( psz_cmd, "crop" ) )
808
    {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
809
        char *psz_end = NULL, *psz_parser = strchr( newval.psz_string, ':' );
810
811
812
813
814
        if( psz_parser )
        {
            /* We're using the 3:4 syntax */
            i_aspect_num = strtol( newval.psz_string, &psz_end, 10 );
            if( psz_end == newval.psz_string || !i_aspect_num ) goto crop_end;
815

816
817
            i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
            if( psz_end == psz_parser || !i_aspect_den ) goto crop_end;
818

819
820
821
822
            i_width = p_vout->fmt_in.i_sar_den*p_vout->fmt_render.i_visible_height *
                i_aspect_num / i_aspect_den / p_vout->fmt_in.i_sar_num;
            i_height = p_vout->fmt_render.i_visible_width*p_vout->fmt_in.i_sar_num *
                i_aspect_den / i_aspect_num / p_vout->fmt_in.i_sar_den;
823

824
825
826
827
828
829
830
831
832
833
834
835
            if( i_width < p_vout->fmt_render.i_visible_width )
            {
                p_vout->fmt_in.i_x_offset = p_vout->fmt_render.i_x_offset +
                    (p_vout->fmt_render.i_visible_width - i_width) / 2;
                p_vout->fmt_in.i_visible_width = i_width;
            }
            else
            {
                p_vout->fmt_in.i_y_offset = p_vout->fmt_render.i_y_offset +
                    (p_vout->fmt_render.i_visible_height - i_height) / 2;
                p_vout->fmt_in.i_visible_height = i_height;
            }
836
837
838
        }
        else
        {
839
840
841
842
843
            psz_parser = strchr( newval.psz_string, 'x' );
            if( psz_parser )
            {
                /* Maybe we're using the <width>x<height>+<left>+<top> syntax */
                unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
844

845
846
                i_crop_width = strtol( newval.psz_string, &psz_end, 10 );
                if( psz_end != psz_parser ) goto crop_end;
847

848
849
850
                psz_parser = strchr( ++psz_end, '+' );
                i_crop_height = strtol( psz_end, &psz_end, 10 );
                if( psz_end != psz_parser ) goto crop_end;
851

852
853
854
                psz_parser = strchr( ++psz_end, '+' );
                i_crop_left = strtol( psz_end, &psz_end, 10 );
                if( psz_end != psz_parser ) goto crop_end;
855

Jean-Paul Saman's avatar
Jean-Paul Saman committed
856
857
                psz_end++;
                i_crop_top = strtol( psz_end, &psz_end, 10 );
858
                if( *psz_end != '\0' ) goto crop_end;
859

860
861
                i_width = i_crop_width;
                p_vout->fmt_in.i_visible_width = i_width;
862

863
864
                i_height = i_crop_height;
                p_vout->fmt_in.i_visible_height = i_height;
865

866
867
868
869
870
871
872
                p_vout->fmt_in.i_x_offset = i_crop_left;
                p_vout->fmt_in.i_y_offset = i_crop_top;
            }
            else
            {
                /* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
                unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
873

874
875
876
                psz_parser = strchr( newval.psz_string, '+' );
                i_crop_left = strtol( newval.psz_string, &psz_end, 10 );
                if( psz_end != psz_parser ) goto crop_end;
877

878
879
880
                psz_parser = strchr( ++psz_end, '+' );
                i_crop_top = strtol( psz_end, &psz_end, 10 );
                if( psz_end != psz_parser ) goto crop_end;
881

882
883
884
                psz_parser = strchr( ++psz_end, '+' );
                i_crop_right = strtol( psz_end, &psz_end, 10 );
                if( psz_end != psz_parser ) goto crop_end;
885

Jean-Paul Saman's avatar
Jean-Paul Saman committed
886
887
                psz_end++;
                i_crop_bottom = strtol( psz_end, &psz_end, 10 );
888
                if( *psz_end != '\0' ) goto crop_end;
889

890
891
892
                i_width = p_vout->fmt_render.i_visible_width
                          - i_crop_left - i_crop_right;
                p_vout->fmt_in.i_visible_width = i_width;
893

894
895
896
                i_height = p_vout->fmt_render.i_visible_height
                           - i_crop_top - i_crop_bottom;
                p_vout->fmt_in.i_visible_height = i_height;
897

898
899
900
                p_vout->fmt_in.i_x_offset = i_crop_left;
                p_vout->fmt_in.i_y_offset = i_crop_top;
            }
901
        }
902
    }
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
    else if( !strcmp( psz_cmd, "crop-top" )
          || !strcmp( psz_cmd, "crop-left" )
          || !strcmp( psz_cmd, "crop-bottom" )
          || !strcmp( psz_cmd, "crop-right" ) )
    {
        unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;

        i_crop_top = var_GetInteger( p_vout, "crop-top" );
        i_crop_left = var_GetInteger( p_vout, "crop-left" );
        i_crop_right = var_GetInteger( p_vout, "crop-right" );
        i_crop_bottom = var_GetInteger( p_vout, "crop-bottom" );

        i_width = p_vout->fmt_render.i_visible_width
                  - i_crop_left - i_crop_right;
        p_vout->fmt_in.i_visible_width = i_width;

        i_height = p_vout->fmt_render.i_visible_height
                   - i_crop_top - i_crop_bottom;
        p_vout->fmt_in.i_visible_height = i_height;

        p_vout->fmt_in.i_x_offset = i_crop_left;
        p_vout->fmt_in.i_y_offset = i_crop_top;
    }
926
927

 crop_end:
928
929
930
    InitWindowSize( p_vout, &p_vout->i_window_width,
                    &p_vout->i_window_height );

931
932
    p_vout->i_changes |= VOUT_CROP_CHANGE;

933
934
935
936
937
938
939
940
941
    msg_Dbg( p_vout, "cropping picture %ix%i to %i,%i,%ix%i",
             p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
             p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
             p_vout->fmt_in.i_visible_width,
             p_vout->fmt_in.i_visible_height );

    return VLC_SUCCESS;
}

942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
static int AspectCallback( vlc_object_t *p_this, char const *psz_cmd,
                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
    unsigned int i_aspect_num, i_aspect_den, i_sar_num, i_sar_den;
    vlc_value_t val;

    char *psz_end, *psz_parser = strchr( newval.psz_string, ':' );

    /* Restore defaults */
    p_vout->fmt_in.i_sar_num = p_vout->fmt_render.i_sar_num;
    p_vout->fmt_in.i_sar_den = p_vout->fmt_render.i_sar_den;
    p_vout->fmt_in.i_aspect = p_vout->fmt_render.i_aspect;
    p_vout->render.i_aspect = p_vout->fmt_render.i_aspect;

    if( !psz_parser ) goto aspect_end;

959
    i_aspect_num = strtol( newval.psz_string, &psz_end, 10 );
960
961
    if( psz_end == newval.psz_string || !i_aspect_num ) goto aspect_end;

962
    i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
963
964
965
966
967
968
969
970
971
972
973
    if( psz_end == psz_parser || !i_aspect_den ) goto aspect_end;

    i_sar_num = i_aspect_num * p_vout->fmt_render.i_visible_height;
    i_sar_den = i_aspect_den * p_vout->fmt_render.i_visible_width;
    vlc_ureduce( &i_sar_num, &i_sar_den, i_sar_num, i_sar_den, 0 );
    p_vout->fmt_in.i_sar_num = i_sar_num;
    p_vout->fmt_in.i_sar_den = i_sar_den;
    p_vout->fmt_in.i_aspect = i_aspect_num * VOUT_ASPECT_FACTOR / i_aspect_den;
    p_vout->render.i_aspect = p_vout->fmt_in.i_aspect;

 aspect_end:
974
975
976
977
978
979
980
981
982
    if( p_vout->i_par_num && p_vout->i_par_den )
    {
        p_vout->fmt_in.i_sar_num *= p_vout->i_par_den;
        p_vout->fmt_in.i_sar_den *= p_vout->i_par_num;
        p_vout->fmt_in.i_aspect = p_vout->fmt_in.i_aspect *
            p_vout->i_par_den / p_vout->i_par_num;
        p_vout->render.i_aspect = p_vout->fmt_in.i_aspect;
    }

983
984
985
986
987
988
989
990
991
    p_vout->i_changes |= VOUT_ASPECT_CHANGE;

    vlc_ureduce( &i_aspect_num, &i_aspect_den,
                 p_vout->fmt_in.i_aspect, VOUT_ASPECT_FACTOR, 0 );
    msg_Dbg( p_vout, "new aspect-ratio %i:%i, sample aspect-ratio %i:%i",
             i_aspect_num, i_aspect_den,
             p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den );

    var_Get( p_vout, "crop", &val );
992
    return CropCallback( p_this, "crop", val, val, 0 );
993
994
995
996

    return VLC_SUCCESS;
}

997
998
999
1000
static int OnTopCallback( vlc_object_t *p_this, char const *psz_cmd,
                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
1001
    playlist_t *p_playlist;
1002
    vout_Control( p_vout, VOUT_SET_STAY_ON_TOP, newval.b_bool );
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013

    p_playlist = (playlist_t *)vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
                                                 FIND_PARENT );
    if( p_playlist )
    {
        /* Modify playlist as well because the vout might have to be restarted */
        var_Create( p_playlist, "video-on-top", VLC_VAR_BOOL );
        var_Set( p_playlist, "video-on-top", newval );

        vlc_object_release( p_playlist );
    }
1014
1015
    return VLC_SUCCESS;
}
1016
1017
1018
1019
1020

static int FullscreenCallback( vlc_object_t *p_this, char const *psz_cmd,
                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
1021
    playlist_t *p_playlist;
1022
1023
1024
1025
    vlc_value_t val;

    p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;

1026
    p_playlist = (playlist_t *)vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
1027
                                                 FIND_PARENT );
1028
    if( p_playlist )
1029
    {
1030
1031
1032
        /* Modify playlist as well because the vout might have to be restarted */
        var_Create( p_playlist, "fullscreen", VLC_VAR_BOOL );
        var_Set( p_playlist, "fullscreen", newval );
1033

1034
        vlc_object_release( p_playlist );
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
    }

    /* Disable "always on top" in fullscreen mode */
    var_Get( p_vout, "video-on-top", &val );
    if( newval.b_bool && val.b_bool )
    {
        val.b_bool = VLC_FALSE;
        vout_Control( p_vout, VOUT_SET_STAY_ON_TOP, val.b_bool );
    }
    else if( !newval.b_bool && val.b_bool )
    {
        vout_Control( p_vout, VOUT_SET_STAY_ON_TOP, val.b_bool );
    }

    val.b_bool = VLC_TRUE;
    var_Set( p_vout, "intf-change", val );
    return VLC_SUCCESS;
}
1053
1054
1055
1056
1057
1058
1059
1060

static int SnapshotCallback( vlc_object_t *p_this, char const *psz_cmd,
                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
    vout_Control( p_vout, VOUT_SNAPSHOT );
    return VLC_SUCCESS;
}