Coverage Report

Created: 2025-08-29 07:30

/src/vlc/src/video_output/vout_intf.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * vout_intf.c : video output interface
3
 *****************************************************************************
4
 * Copyright (C) 2000-2007 VLC authors and VideoLAN
5
 *
6
 * Authors: Gildas Bazin <gbazin@videolan.org>
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program; if not, write to the Free Software Foundation,
20
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21
 *****************************************************************************/
22
23
/*****************************************************************************
24
 * Preamble
25
 *****************************************************************************/
26
27
#ifdef HAVE_CONFIG_H
28
# include "config.h"
29
#endif
30
31
#include <vlc_common.h>
32
33
#include <stdio.h>
34
#include <stdlib.h>                                                /* free() */
35
#include <assert.h>
36
37
#include <vlc_block.h>
38
#include <vlc_modules.h>
39
40
#include <vlc_vout.h>
41
#include <vlc_vout_osd.h>
42
#include <vlc_strings.h>
43
#include <vlc_charset.h>
44
#include <vlc_spu.h>
45
#include <vlc_subpicture.h>
46
#include "vout_internal.h"
47
#include "snapshot.h"
48
49
/*****************************************************************************
50
 * Local prototypes
51
 *****************************************************************************/
52
/* Object variables callbacks */
53
static int CropCallback( vlc_object_t *, char const *,
54
                         vlc_value_t, vlc_value_t, void * );
55
static int CropBorderCallback( 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 AutoScaleCallback( vlc_object_t *, char const *,
60
                              vlc_value_t, vlc_value_t, void * );
61
static int FitCallback( vlc_object_t *, char const *,
62
                        vlc_value_t, vlc_value_t, void * );
63
static int ZoomCallback( vlc_object_t *, char const *,
64
                         vlc_value_t, vlc_value_t, void * );
65
static int AboveCallback( vlc_object_t *, char const *,
66
                          vlc_value_t, vlc_value_t, void * );
67
static int WallPaperCallback( vlc_object_t *, char const *,
68
                              vlc_value_t, vlc_value_t, void * );
69
static int FullscreenCallback( vlc_object_t *, char const *,
70
                               vlc_value_t, vlc_value_t, void * );
71
static int SnapshotCallback( vlc_object_t *, char const *,
72
                             vlc_value_t, vlc_value_t, void * );
73
static int VideoFilterCallback( vlc_object_t *, char const *,
74
                                vlc_value_t, vlc_value_t, void * );
75
static int SubSourceCallback( vlc_object_t *, char const *,
76
                              vlc_value_t, vlc_value_t, void * );
77
static int SubFilterCallback( vlc_object_t *, char const *,
78
                              vlc_value_t, vlc_value_t, void * );
79
static int SubMarginCallback( vlc_object_t *, char const *,
80
                              vlc_value_t, vlc_value_t, void * );
81
static int SecondarySubMarginCallback( vlc_object_t *, char const *,
82
                                       vlc_value_t, vlc_value_t, void * );
83
static int ViewpointCallback( vlc_object_t *, char const *,
84
                              vlc_value_t, vlc_value_t, void * );
85
static int Stereo3DCallback( vlc_object_t *, char const *,
86
                             vlc_value_t, vlc_value_t, void * );
87
88
static int OverrideProjectionCallback( vlc_object_t *, char const *,
89
                              vlc_value_t, vlc_value_t, void * );
90
91
static int ChangeProjectionCallback( vlc_object_t *, char const *,
92
                              vlc_value_t, vlc_value_t, void * );
93
94
/*****************************************************************************
95
 * vout_IntfInit: called during the vout creation to initialise misc things.
96
 *****************************************************************************/
97
static const struct
98
{
99
    double f_value;
100
    char psz_label[13];
101
} p_zoom_values[] = {
102
    { 0.25, N_("1:4 Quarter") },
103
    { 0.5, N_("1:2 Half") },
104
    { 1, N_("1:1 Original") },
105
    { 2, N_("2:1 Double") },
106
};
107
108
static const struct
109
{
110
    char psz_value[8];
111
    char psz_label[8];
112
} p_crop_values[] = {
113
    { "", N_("Default") },
114
    { "16:10", "16:10" },
115
    { "16:9", "16:9" },
116
    { "4:3", "4:3" },
117
    { "185:100", "1.85:1" },
118
    { "221:100", "2.21:1" },
119
    { "235:100", "2.35:1" },
120
    { "239:100", "2.39:1" },
121
    { "5:3", "5:3" },
122
    { "5:4", "5:4" },
123
    { "1:1", "1:1" },
124
};
125
126
static const struct
127
{
128
    char psz_value[8];
129
    char psz_label[12];
130
} p_aspect_ratio_values[] = {
131
    { "", N_("Default") },
132
    { "16:9", "16:9" },
133
    { "4:3", "4:3" },
134
    { "1:1", "1:1" },
135
    { "16:10", "16:10" },
136
    { "221:100", "2.21:1" },
137
    { "235:100", "2.35:1" },
138
    { "239:100", "2.39:1" },
139
    { "5:4", "5:4" },
140
    { "fill", N_("Fill Window") },
141
};
142
143
static const struct
144
{
145
    enum vlc_video_fitting fit;
146
    char psz_label[15];
147
} p_fit_values[] = {
148
    { VLC_VIDEO_FIT_NONE,    N_("None") },
149
    { VLC_VIDEO_FIT_SMALLER, N_("Inside Window") },
150
    { VLC_VIDEO_FIT_LARGER,  N_("Outside Window") },
151
    { VLC_VIDEO_FIT_WIDTH,   N_("Window Width") },
152
    { VLC_VIDEO_FIT_HEIGHT,  N_("Window Height") },
153
};
154
155
static const struct
156
{
157
    int i_value;
158
    char psz_label[13];
159
} p_3D_output_format_values[] = {
160
    { VIDEO_STEREO_OUTPUT_AUTO, N_("Auto") },
161
    { VIDEO_STEREO_OUTPUT_STEREO, N_("Stereo") },
162
    { VIDEO_STEREO_OUTPUT_LEFT_ONLY, N_("Left Only") },
163
    { VIDEO_STEREO_OUTPUT_RIGHT_ONLY, N_("Right Only") },
164
    { VIDEO_STEREO_OUTPUT_SIDE_BY_SIDE, N_("Side-by-Side") },
165
};
166
167
static void AddCustomRatios( vout_thread_t *p_vout, const char *psz_var,
168
                             char *psz_list )
169
0
{
170
0
    assert( psz_list );
171
172
0
    char *psz_cur = psz_list;
173
0
    char *psz_next;
174
0
    while( psz_cur && *psz_cur )
175
0
    {
176
0
        vlc_value_t val;
177
0
        psz_next = strchr( psz_cur, ',' );
178
0
        if( psz_next )
179
0
        {
180
0
            *psz_next = '\0';
181
0
            psz_next++;
182
0
        }
183
0
        val.psz_string = psz_cur;
184
0
        var_Change( p_vout, psz_var, VLC_VAR_ADDCHOICE, val,
185
0
                    (const char *)psz_cur );
186
0
        psz_cur = psz_next;
187
0
    }
188
0
}
189
190
enum vlc_video_fitting var_InheritFit(vlc_object_t *obj)
191
0
{
192
0
    int64_t v = var_InheritInteger(obj, "fit");
193
    /* Safe variable => paranoid checks */
194
0
    switch (v) {
195
0
        case VLC_VIDEO_FIT_SMALLER:
196
0
        case VLC_VIDEO_FIT_LARGER:
197
0
        case VLC_VIDEO_FIT_WIDTH:
198
0
        case VLC_VIDEO_FIT_HEIGHT:
199
0
            return v;
200
0
        default:
201
0
            return VLC_VIDEO_FIT_SMALLER;
202
0
    }
203
0
}
204
205
void vout_CreateVars( vout_thread_t *p_vout )
206
0
{
207
0
    vlc_value_t val;
208
0
    char *psz_buf;
209
210
    /* Create a few object variables we'll need later on */
211
0
    var_Create( p_vout, "snapshot-num", VLC_VAR_INTEGER );
212
0
    var_SetInteger( p_vout, "snapshot-num", 1 );
213
214
0
    var_Create( p_vout, "width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
215
0
    var_Create( p_vout, "height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
216
0
    var_Create( p_vout, "align", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
217
218
0
    var_Create( p_vout, "mouse-hide-timeout",
219
0
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
220
221
    /* Add variables to manage scaling video */
222
0
    var_Create( p_vout, "autoscale", VLC_VAR_BOOL | VLC_VAR_DOINHERIT
223
0
                | VLC_VAR_ISCOMMAND );
224
225
0
    var_Create( p_vout, "zoom", VLC_VAR_FLOAT | VLC_VAR_ISCOMMAND |
226
0
                VLC_VAR_DOINHERIT );
227
0
    var_Change( p_vout, "zoom", VLC_VAR_SETTEXT, _("Zoom") );
228
0
    for( size_t i = 0; i < ARRAY_SIZE(p_zoom_values); i++ )
229
0
    {
230
0
        val.f_float = p_zoom_values[i].f_value;
231
0
        var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, val,
232
0
                    vlc_gettext( p_zoom_values[i].psz_label ) );
233
0
    }
234
235
0
    var_Create( p_vout, "video-stereo-mode", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
236
0
    var_Change( p_vout, "video-stereo-mode", VLC_VAR_SETTEXT, _("video-stereo-output"), NULL );
237
238
0
    for( size_t i = 0; i < ARRAY_SIZE(p_3D_output_format_values); i++ )
239
0
    {
240
0
        val.i_int = p_3D_output_format_values[i].i_value;
241
0
        var_Change( p_vout, "video-stereo-mode", VLC_VAR_ADDCHOICE, val,
242
0
                    vlc_gettext( p_3D_output_format_values[i].psz_label ) );
243
0
    }
244
245
    /* Crop offset vars */
246
0
    var_Create( p_vout, "crop-left", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
247
0
    var_Create( p_vout, "crop-top", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
248
0
    var_Create( p_vout, "crop-right", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
249
0
    var_Create( p_vout, "crop-bottom", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
250
251
    /* Crop object var */
252
0
    var_Create( p_vout, "crop", VLC_VAR_STRING | VLC_VAR_ISCOMMAND |
253
0
                VLC_VAR_DOINHERIT );
254
0
    var_Change( p_vout, "crop", VLC_VAR_SETTEXT, _("Crop") );
255
256
0
    for( size_t i = 0; i < ARRAY_SIZE(p_crop_values); i++ )
257
0
    {
258
0
        val.psz_string = (char*)p_crop_values[i].psz_value;
259
0
        var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, val,
260
0
                    p_crop_values[i].psz_label );
261
0
    }
262
263
    /* Add custom crop ratios */
264
0
    psz_buf = var_CreateGetNonEmptyString( p_vout, "custom-crop-ratios" );
265
0
    if( psz_buf )
266
0
    {
267
0
        AddCustomRatios( p_vout, "crop", psz_buf );
268
0
        free( psz_buf );
269
0
    }
270
271
    /* Monitor pixel aspect-ratio */
272
0
    var_Create( p_vout, "monitor-par", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
273
274
    /* Aspect-ratio object var */
275
0
    var_Create( p_vout, "aspect-ratio", VLC_VAR_STRING | VLC_VAR_ISCOMMAND |
276
0
                VLC_VAR_DOINHERIT );
277
0
    var_Change( p_vout, "aspect-ratio", VLC_VAR_SETTEXT, _("Aspect ratio") );
278
279
0
    for( size_t i = 0; i < ARRAY_SIZE(p_aspect_ratio_values); i++ )
280
0
    {
281
0
        val.psz_string = (char*)p_aspect_ratio_values[i].psz_value;
282
0
        var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, val,
283
0
                    vlc_gettext(p_aspect_ratio_values[i].psz_label) );
284
0
    }
285
286
    /* Add custom aspect ratios */
287
0
    psz_buf = var_CreateGetNonEmptyString( p_vout, "custom-aspect-ratios" );
288
0
    if( psz_buf )
289
0
    {
290
0
        AddCustomRatios( p_vout, "aspect-ratio", psz_buf );
291
0
        free( psz_buf );
292
0
    }
293
294
    /* display fit */
295
0
    var_Create( p_vout, "fit", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND |
296
0
                VLC_VAR_DOINHERIT );
297
0
    var_Change( p_vout, "fit", VLC_VAR_SETTEXT, _("Fit Mode") );
298
299
0
    for( size_t i = 0; i < ARRAY_SIZE(p_fit_values); i++ )
300
0
    {
301
0
        val.i_int = p_fit_values[i].fit;
302
0
        var_Change( p_vout, "fit", VLC_VAR_ADDCHOICE, val,
303
0
                    p_fit_values[i].psz_label );
304
0
    }
305
306
    /* Add a variable to indicate if the window should be on top of others */
307
0
    var_Create( p_vout, "video-on-top", VLC_VAR_BOOL | VLC_VAR_DOINHERIT
308
0
                | VLC_VAR_ISCOMMAND );
309
0
    var_Change( p_vout, "video-on-top", VLC_VAR_SETTEXT,
310
0
                _("Always on top") );
311
312
    /* Add a variable to indicate if the window should be below all others */
313
0
    var_Create( p_vout, "video-wallpaper", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
314
315
    /* Add a variable to indicate whether we want window decoration or not */
316
0
    var_Create( p_vout, "video-deco", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
317
318
    /* Add a fullscreen variable */
319
0
    var_Create( p_vout, "fullscreen",
320
0
                VLC_VAR_BOOL | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
321
0
    var_Change( p_vout, "fullscreen", VLC_VAR_SETTEXT, _("Fullscreen") );
322
323
    /* Add a snapshot variable */
324
0
    var_Create( p_vout, "video-snapshot", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
325
0
    var_Change( p_vout, "video-snapshot", VLC_VAR_SETTEXT, _("Snapshot") );
326
327
    /* Add a video-filter variable */
328
0
    var_Create( p_vout, "video-filter",
329
0
                VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
330
331
    /* Add a sub-source variable */
332
0
    var_Create( p_vout, "sub-source",
333
0
                VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
334
335
    /* Add a sub-filter variable */
336
0
    var_Create( p_vout, "sub-filter",
337
0
                VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
338
339
    /* Add sub-margin variable */
340
0
    var_Create( p_vout, "sub-margin",
341
0
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
342
343
    /* Add secondary-sub-margin variable (dual subtitles) */
344
0
    var_Create( p_vout, "secondary-sub-margin",
345
0
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
346
0
    var_AddCallback( p_vout, "secondary-sub-margin", SecondarySubMarginCallback, NULL );
347
348
    /* Mouse coordinates */
349
0
    var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
350
0
    var_Create( p_vout, "mouse-moved", VLC_VAR_COORDS );
351
352
    /* Device orientation */
353
0
    var_Create( p_vout, "viewpoint-moved", VLC_VAR_ADDRESS );
354
355
    /* Viewpoint */
356
0
    var_Create( p_vout, "viewpoint", VLC_VAR_ADDRESS  );
357
0
    var_Create( p_vout, "viewpoint-changeable", VLC_VAR_BOOL );
358
359
    /* SPU in full window */
360
0
    var_Create( p_vout, "spu-fill", VLC_VAR_BOOL | VLC_VAR_DOINHERIT
361
0
                | VLC_VAR_ISCOMMAND );
362
363
0
    var_Create(p_vout, "override-projection", VLC_VAR_BOOL);
364
0
    var_SetBool(p_vout, "override-projection", false);
365
366
0
    var_Create(p_vout, "projection-mode", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
367
0
}
368
369
void vout_IntfInit( vout_thread_t *p_vout )
370
0
{
371
0
    var_AddCallback( p_vout, "autoscale", AutoScaleCallback, NULL );
372
0
    var_AddCallback( p_vout, "fit", FitCallback, NULL );
373
0
    var_AddCallback( p_vout, "zoom", ZoomCallback, NULL );
374
0
    var_AddCallback( p_vout, "crop-left", CropBorderCallback, NULL );
375
0
    var_AddCallback( p_vout, "crop-top", CropBorderCallback, NULL );
376
0
    var_AddCallback( p_vout, "crop-right", CropBorderCallback, NULL );
377
0
    var_AddCallback( p_vout, "crop-bottom", CropBorderCallback, NULL );
378
0
    var_AddCallback( p_vout, "crop", CropCallback, NULL );
379
0
    var_AddCallback( p_vout, "aspect-ratio", AspectCallback, NULL );
380
0
    var_AddCallback( p_vout, "video-on-top", AboveCallback, NULL );
381
0
    var_AddCallback( p_vout, "video-wallpaper", WallPaperCallback, NULL );
382
0
    var_AddCallback( p_vout, "fullscreen", FullscreenCallback, NULL );
383
0
    var_AddCallback( p_vout, "video-snapshot", SnapshotCallback, NULL );
384
0
    var_AddCallback( p_vout, "video-filter", VideoFilterCallback, NULL );
385
0
    var_AddCallback( p_vout, "sub-source", SubSourceCallback, NULL );
386
0
    var_AddCallback( p_vout, "sub-filter", SubFilterCallback, NULL );
387
0
    var_AddCallback( p_vout, "sub-margin", SubMarginCallback, NULL );
388
0
    var_AddCallback( p_vout, "viewpoint", ViewpointCallback, NULL );
389
0
    var_AddCallback( p_vout, "override-projection", OverrideProjectionCallback, NULL );
390
0
    var_AddCallback( p_vout, "projection-mode", ChangeProjectionCallback, NULL );
391
0
    var_AddCallback(p_vout, "video-stereo-mode", Stereo3DCallback, NULL);
392
0
}
393
394
void vout_IntfReinit( vout_thread_t *p_vout )
395
0
{
396
0
    var_TriggerCallback( p_vout, "video-on-top" );
397
0
    var_TriggerCallback( p_vout, "video-wallpaper" );
398
399
0
    var_TriggerCallback( p_vout, "video-filter" );
400
0
    var_TriggerCallback( p_vout, "sub-source" );
401
0
    var_TriggerCallback( p_vout, "sub-filter" );
402
    /* !Warn those will trigger also vlc_player_vout_OSDCallback and
403
        cause unwanted OSD on vout start. Filter out it there. */
404
0
    var_TriggerCallback( p_vout, "sub-margin" );
405
0
    var_TriggerCallback( p_vout, "secondary-sub-margin" );
406
407
0
    var_TriggerCallback( p_vout, "projection-mode" );
408
0
    var_TriggerCallback(p_vout, "video-stereo-mode");
409
0
}
410
411
void vout_IntfDeinit(vlc_object_t *obj)
412
0
{
413
0
    var_DelCallback(obj, "viewpoint", ViewpointCallback, NULL);
414
0
    var_DelCallback(obj, "sub-margin", SubMarginCallback, NULL);
415
0
    var_DelCallback(obj, "secondary-sub-margin", SecondarySubMarginCallback, NULL);
416
0
    var_DelCallback(obj, "sub-filter", SubFilterCallback, NULL);
417
0
    var_DelCallback(obj, "sub-source", SubSourceCallback, NULL);
418
0
    var_DelCallback(obj, "video-filter", VideoFilterCallback, NULL);
419
0
    var_DelCallback(obj, "video-snapshot", SnapshotCallback, NULL);
420
0
    var_DelCallback(obj, "fullscreen", FullscreenCallback, NULL);
421
0
    var_DelCallback(obj, "video-wallpaper", WallPaperCallback, NULL);
422
0
    var_DelCallback(obj, "video-on-top", AboveCallback, NULL);
423
0
    var_DelCallback(obj, "aspect-ratio", AspectCallback, NULL);
424
0
    var_DelCallback(obj, "crop", CropCallback, NULL);
425
0
    var_DelCallback(obj, "crop-bottom", CropBorderCallback, NULL);
426
0
    var_DelCallback(obj, "crop-right", CropBorderCallback, NULL);
427
0
    var_DelCallback(obj, "crop-top", CropBorderCallback, NULL);
428
0
    var_DelCallback(obj, "crop-left", CropBorderCallback, NULL);
429
0
    var_DelCallback(obj, "zoom", ZoomCallback, NULL);
430
0
    var_DelCallback(obj, "fit", FitCallback, NULL);
431
0
    var_DelCallback(obj, "autoscale", AutoScaleCallback, NULL);
432
0
    var_DelCallback(obj, "override-projection", OverrideProjectionCallback, NULL);
433
0
    var_DelCallback(obj, "projection-mode", ChangeProjectionCallback, NULL);
434
0
    var_DelCallback(obj, "video-stereo-mode", Stereo3DCallback, NULL);
435
0
}
436
437
/*****************************************************************************
438
 * vout_Snapshot: generates a snapshot.
439
 *****************************************************************************/
440
/**
441
 * This function will inject a subpicture into the vout with the provided
442
 * picture
443
 */
444
static int VoutSnapshotPip( vout_thread_t *p_vout, picture_t *p_pic )
445
0
{
446
0
    subpicture_t *p_subpic = subpicture_NewFromPicture( VLC_OBJECT(p_vout),
447
0
                                                        p_pic, VLC_CODEC_YUVA );
448
0
    if( !p_subpic )
449
0
        return VLC_EGENERIC;
450
451
    /* FIXME SPU_DEFAULT_CHANNEL is not good (used by the text) but
452
     * hardcoded 0 doesn't seem right */
453
0
    p_subpic->i_channel = 0;
454
0
    p_subpic->i_start = vlc_tick_now();
455
0
    p_subpic->i_stop  = p_subpic->i_start + VLC_TICK_FROM_SEC(4);
456
0
    p_subpic->b_ephemer = true;
457
0
    p_subpic->b_fade = true;
458
459
    /* Reduce the picture to 1/4^2 of the screen */
460
0
    p_subpic->i_original_picture_width  *= 4;
461
0
    p_subpic->i_original_picture_height *= 4;
462
463
0
    vout_PutSubpicture( p_vout, p_subpic );
464
0
    return VLC_SUCCESS;
465
0
}
466
467
/**
468
 * This function will display the name and a PIP of the provided snapshot
469
 */
470
static void VoutOsdSnapshot( vout_thread_t *p_vout, picture_t *p_pic, const char *psz_filename )
471
0
{
472
0
    msg_Dbg( p_vout, "snapshot taken (%s)", psz_filename );
473
0
    vout_OSDMessage( p_vout, VOUT_SPU_CHANNEL_OSD, "%s", psz_filename );
474
475
0
    if( var_InheritBool( p_vout, "snapshot-preview" ) )
476
0
    {
477
0
        if( VoutSnapshotPip( p_vout, p_pic ) )
478
0
            msg_Warn( p_vout, "Failed to display snapshot" );
479
0
    }
480
0
}
481
482
/**
483
 * This function will handle a snapshot request
484
 */
485
static void VoutSaveSnapshot( vout_thread_t *p_vout )
486
0
{
487
0
    char *psz_path = var_InheritString( p_vout, "snapshot-path" );
488
0
    char *psz_format = var_InheritString( p_vout, "snapshot-format" );
489
0
    char *psz_prefix = var_InheritString( p_vout, "snapshot-prefix" );
490
491
    /* */
492
0
    picture_t *p_picture;
493
0
    block_t *p_image;
494
495
    /* 500ms timeout
496
     * XXX it will cause trouble with low fps video (< 2fps) */
497
0
    if( vout_GetSnapshot( p_vout, &p_image, &p_picture, NULL, psz_format, VLC_TICK_FROM_MS(500) ) )
498
0
    {
499
0
        p_picture = NULL;
500
0
        p_image = NULL;
501
0
        goto exit;
502
0
    }
503
504
0
    if( !psz_path )
505
0
    {
506
0
        psz_path = vout_snapshot_GetDirectory();
507
0
        if( !psz_path )
508
0
        {
509
0
            msg_Err( p_vout, "no path specified for snapshots" );
510
0
            goto exit;
511
0
        }
512
0
    }
513
514
0
    vout_snapshot_save_cfg_t cfg;
515
0
    memset( &cfg, 0, sizeof(cfg) );
516
0
    cfg.is_sequential = var_InheritBool( p_vout, "snapshot-sequential" );
517
0
    cfg.sequence = var_GetInteger( p_vout, "snapshot-num" );
518
0
    cfg.path = psz_path;
519
0
    cfg.format = psz_format;
520
0
    cfg.prefix_fmt = psz_prefix;
521
522
0
    char *psz_filename;
523
0
    int  i_sequence;
524
0
    if (vout_snapshot_SaveImage( &psz_filename, &i_sequence,
525
0
                                 p_image, p_vout, &cfg ) )
526
0
        goto exit;
527
0
    if( cfg.is_sequential )
528
0
        var_SetInteger( p_vout, "snapshot-num", i_sequence + 1 );
529
530
0
    VoutOsdSnapshot( p_vout, p_picture, psz_filename );
531
532
    /* signal creation of a new snapshot file */
533
0
    var_SetString( vlc_object_instance(p_vout), "snapshot-file", psz_filename );
534
535
0
    free( psz_filename );
536
537
0
exit:
538
0
    if( p_image )
539
0
        block_Release( p_image );
540
0
    if( p_picture )
541
0
        picture_Release( p_picture );
542
0
    free( psz_prefix );
543
0
    free( psz_format );
544
0
    free( psz_path );
545
0
}
546
547
bool vout_ParseCrop(struct vout_crop *restrict cfg, const char *crop_str)
548
0
{
549
0
    float fnum, fden;
550
551
0
    if (sscanf(crop_str, "%u:%u", &cfg->ratio.num, &cfg->ratio.den) == 2) {
552
0
        if (cfg->ratio.num != 0 && cfg->ratio.den != 0)
553
0
            cfg->mode = VOUT_CROP_RATIO;
554
0
        else
555
0
            cfg->mode = VOUT_CROP_NONE;
556
0
    } else if (sscanf(crop_str, "%ux%u+%u+%u",
557
0
                      &cfg->window.width, &cfg->window.height,
558
0
                      &cfg->window.x, &cfg->window.y) == 4) {
559
0
        cfg->mode = VOUT_CROP_WINDOW;
560
0
    } else if (sscanf(crop_str, "%u+%u+%u+%u",
561
0
                      &cfg->border.left, &cfg->border.top,
562
0
                      &cfg->border.right, &cfg->border.bottom) == 4) {
563
0
        cfg->mode = VOUT_CROP_BORDER;
564
0
    } else if (vlc_sscanf_c(crop_str, "%f:%f", &fnum, &fden) == 2) {
565
0
        long num = lroundf(ldexp(fnum, 24/*-bit mantissa */));
566
0
        long den = lroundf(ldexp(fden, 24));
567
0
        long gcd = GCD(num, den);
568
569
0
        cfg->mode = VOUT_CROP_RATIO;
570
0
        cfg->ratio.num = num / gcd;
571
0
        cfg->ratio.den = den / gcd;
572
0
    } else if (*crop_str == '\0') {
573
0
        cfg->mode = VOUT_CROP_NONE;
574
0
    } else {
575
0
        return false;
576
0
    }
577
0
    return true;
578
0
}
579
580
/*****************************************************************************
581
 * Object variables callbacks
582
 *****************************************************************************/
583
static int CropCallback( vlc_object_t *object, char const *cmd,
584
                         vlc_value_t oldval, vlc_value_t newval, void *data )
585
0
{
586
0
    vout_thread_t *vout = (vout_thread_t *)object;
587
0
    VLC_UNUSED(cmd); VLC_UNUSED(oldval); VLC_UNUSED(data);
588
0
    struct vout_crop crop;
589
590
0
    if (vout_ParseCrop(&crop, newval.psz_string))
591
0
        vout_ChangeCrop(vout, &crop);
592
0
    else
593
0
        msg_Err(object, "Unknown crop format (%s)", newval.psz_string);
594
595
0
    return VLC_SUCCESS;
596
0
}
597
598
static int CropBorderCallback(vlc_object_t *object, char const *cmd,
599
                              vlc_value_t oldval, vlc_value_t newval, void *data)
600
0
{
601
0
    char buf[4 * 21];
602
603
0
    snprintf(buf, sizeof (buf), "%"PRIu64"+%"PRIu64"+%"PRIu64"+%"PRIu64,
604
0
             var_GetInteger(object, "crop-left"),
605
0
             var_GetInteger(object, "crop-top"),
606
0
             var_GetInteger(object, "crop-right"),
607
0
             var_GetInteger(object, "crop-bottom"));
608
0
    var_SetString(object, "crop", buf);
609
610
0
    VLC_UNUSED(cmd); VLC_UNUSED(oldval); VLC_UNUSED(data); VLC_UNUSED(newval);
611
0
    return VLC_SUCCESS;
612
0
}
613
614
bool GetAspectRatio(const char *ar_str, vlc_rational_t *ar)
615
0
{
616
0
    if (*ar_str == '\0') {
617
0
        *ar = VLC_DAR_FROM_SOURCE;
618
0
        return true;
619
0
    }
620
0
    if (strcmp(ar_str,"fill")==0) {
621
0
        *ar = VLC_DAR_FILL_DISPLAY;
622
0
        return true;
623
0
    }
624
0
    if (sscanf(ar_str, "%u:%u", &ar->num, &ar->den) == 2 &&
625
0
        (ar->num != 0) == (ar->den != 0))
626
0
        return true;
627
0
    return false;
628
0
}
629
630
static int AspectCallback( vlc_object_t *object, char const *cmd,
631
                         vlc_value_t oldval, vlc_value_t newval, void *data )
632
0
{
633
0
    vout_thread_t *vout = (vout_thread_t *)object;
634
0
    VLC_UNUSED(cmd); VLC_UNUSED(oldval); VLC_UNUSED(data);
635
0
    vlc_rational_t ar;
636
637
0
    if (GetAspectRatio(newval.psz_string, &ar))
638
0
        vout_ChangeDisplayAspectRatio(vout, ar.num, ar.den);
639
0
    return VLC_SUCCESS;
640
0
}
641
642
static int AutoScaleCallback( vlc_object_t *obj, char const *name,
643
                              vlc_value_t prev, vlc_value_t cur, void *data )
644
0
{
645
0
    vout_thread_t *p_vout = (vout_thread_t *)obj;
646
0
    enum vlc_video_fitting fit = cur.b_bool ? var_InheritFit(obj)
647
0
                                            : VLC_VIDEO_FIT_NONE;
648
649
0
    (void) name; (void) prev; (void) data;
650
0
    vout_ChangeDisplayFitting(p_vout, fit);
651
0
    return VLC_SUCCESS;
652
0
}
653
654
static int FitCallback( vlc_object_t *obj, char const *name,
655
                        vlc_value_t prev, vlc_value_t cur, void *data )
656
0
{
657
0
    vout_thread_t *p_vout = (vout_thread_t *)obj;
658
0
    enum vlc_video_fitting fit = cur.i_int;
659
660
0
    (void) name; (void) prev; (void) data;
661
0
    vout_ChangeDisplayFitting(p_vout, fit);
662
0
    return VLC_SUCCESS;
663
0
}
664
665
static int OverrideProjectionCallback( vlc_object_t *obj, char const *name,
666
                              vlc_value_t prev, vlc_value_t cur, void *data )
667
0
{
668
0
    VLC_UNUSED(name); VLC_UNUSED(prev); VLC_UNUSED(data);
669
0
    vout_thread_t *vout = (vout_thread_t *)obj;
670
671
0
    vout_OSDMessage(vout, VOUT_SPU_CHANNEL_OSD, "Projection: %s", cur.b_bool ? "disabled" : "enabled");
672
0
    vout_ToggleProjection(vout, !cur.b_bool);
673
0
    return VLC_SUCCESS;
674
0
}
675
676
static int ChangeProjectionCallback( vlc_object_t *obj, char const *name,
677
                              vlc_value_t prev, vlc_value_t cur, void *data )
678
0
{
679
0
    VLC_UNUSED(name); VLC_UNUSED(prev); VLC_UNUSED(data);
680
0
    vout_thread_t *vout = (vout_thread_t *)obj;
681
682
0
    const char *projection;
683
0
    switch(cur.i_int)
684
0
    {
685
0
        case -1:                                        projection = "source"; break;
686
0
        case PROJECTION_MODE_RECTANGULAR:               projection = "rectangular"; break;
687
0
        case PROJECTION_MODE_EQUIRECTANGULAR:           projection = "equirectangular"; break;
688
0
        case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD:   projection = "cubemap (standard)"; break;
689
0
        default: projection = "unknown"; break;
690
0
    }
691
692
0
    vout_OSDMessage(vout, VOUT_SPU_CHANNEL_OSD, "Projection: %s", projection);
693
0
    if (cur.i_int == -1)
694
0
    {
695
0
        vout_ResetProjection(vout);
696
0
        return VLC_SUCCESS;
697
0
    }
698
0
    else if (cur.i_int < 0 || cur.i_int > (int)PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD)
699
0
    {
700
0
        return VLC_EGENERIC;
701
0
    }
702
703
0
    vout_ChangeProjection(vout, cur.i_int);
704
0
    return VLC_SUCCESS;
705
0
}
706
707
static int ZoomCallback( vlc_object_t *obj, char const *name,
708
                         vlc_value_t prev, vlc_value_t cur, void *data )
709
0
{
710
0
    vout_thread_t *p_vout = (vout_thread_t *)obj;
711
712
0
    (void) name; (void) prev; (void) data;
713
0
    vout_ChangeZoom(p_vout, 1000 * cur.f_float, 1000);
714
0
    return VLC_SUCCESS;
715
0
}
716
717
static int Stereo3DCallback( vlc_object_t *obj, char const *name,
718
                         vlc_value_t prev, vlc_value_t cur, void *data )
719
0
{
720
0
    vout_thread_t *p_vout = (vout_thread_t *)obj;
721
0
    (void) name; (void) prev; (void) data;
722
0
    vout_ControlChangeStereo( p_vout, cur.i_int );
723
0
    return VLC_SUCCESS;
724
0
}
725
726
static int AboveCallback( vlc_object_t *obj, char const *name,
727
                          vlc_value_t prev, vlc_value_t cur, void *data )
728
0
{
729
0
    vout_ChangeWindowState((vout_thread_t *)obj,
730
0
        cur.b_bool ? VLC_WINDOW_STATE_ABOVE : VLC_WINDOW_STATE_NORMAL);
731
0
    (void) name; (void) prev; (void) data;
732
0
    return VLC_SUCCESS;
733
0
}
734
735
static int WallPaperCallback( vlc_object_t *obj, char const *name,
736
                              vlc_value_t prev, vlc_value_t cur, void *data )
737
0
{
738
0
    vout_thread_t *vout = (vout_thread_t *)obj;
739
740
0
    if( cur.b_bool )
741
0
    {
742
0
        vout_ChangeWindowState(vout, VLC_WINDOW_STATE_BELOW);
743
0
        vout_ChangeFullscreen(vout, NULL);
744
0
    }
745
0
    else
746
0
    {
747
0
        var_TriggerCallback( obj, "fullscreen" );
748
0
        var_TriggerCallback( obj, "video-on-top" );
749
0
    }
750
0
    (void) name; (void) prev; (void) data;
751
0
    return VLC_SUCCESS;
752
0
}
753
754
static int FullscreenCallback( vlc_object_t *p_this, char const *psz_cmd,
755
                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
756
0
{
757
0
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
758
0
    (void)psz_cmd; (void) oldval; (void)p_data;
759
760
0
    if( newval.b_bool )
761
0
        vout_ChangeFullscreen(p_vout, NULL);
762
0
    else
763
0
        vout_ChangeWindowed(p_vout);
764
0
    return VLC_SUCCESS;
765
0
}
766
767
static int SnapshotCallback( vlc_object_t *p_this, char const *psz_cmd,
768
                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
769
0
{
770
0
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
771
0
    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
772
0
    VLC_UNUSED(newval); VLC_UNUSED(p_data);
773
774
0
    VoutSaveSnapshot( p_vout );
775
0
    return VLC_SUCCESS;
776
0
}
777
778
static int VideoFilterCallback( vlc_object_t *p_this, char const *psz_cmd,
779
                                vlc_value_t oldval, vlc_value_t newval, void *p_data)
780
0
{
781
0
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
782
0
    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
783
784
0
    vout_ControlChangeFilters( p_vout, newval.psz_string );
785
0
    return VLC_SUCCESS;
786
0
}
787
788
static int SubSourceCallback( vlc_object_t *p_this, char const *psz_cmd,
789
                              vlc_value_t oldval, vlc_value_t newval, void *p_data)
790
0
{
791
0
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
792
0
    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
793
794
0
    vout_ControlChangeSubSources( p_vout, newval.psz_string );
795
0
    return VLC_SUCCESS;
796
0
}
797
798
static int SubFilterCallback( vlc_object_t *p_this, char const *psz_cmd,
799
                              vlc_value_t oldval, vlc_value_t newval, void *p_data)
800
0
{
801
0
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
802
0
    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
803
804
0
    vout_ControlChangeSubFilters( p_vout, newval.psz_string );
805
0
    return VLC_SUCCESS;
806
0
}
807
808
static int SubMarginCallback( vlc_object_t *p_this, char const *psz_cmd,
809
                              vlc_value_t oldval, vlc_value_t newval, void *p_data)
810
0
{
811
0
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
812
0
    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
813
814
0
    vout_ChangeSpuChannelMargin(p_vout, VLC_VOUT_ORDER_PRIMARY, newval.i_int);
815
0
    return VLC_SUCCESS;
816
0
}
817
818
static int SecondarySubMarginCallback( vlc_object_t *p_this, char const *psz_cmd,
819
                              vlc_value_t oldval, vlc_value_t newval, void *p_data)
820
0
{
821
0
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
822
0
    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
823
824
0
    vout_ChangeSpuChannelMargin(p_vout, VLC_VOUT_ORDER_SECONDARY, newval.i_int);
825
0
    return VLC_SUCCESS;
826
0
}
827
828
static int ViewpointCallback( vlc_object_t *p_this, char const *psz_cmd,
829
                              vlc_value_t oldval, vlc_value_t newval, void *p_data)
830
0
{
831
0
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
832
0
    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
833
834
0
    if( newval.p_address != NULL )
835
0
        vout_ChangeViewpoint(p_vout, newval.p_address);
836
0
    return VLC_SUCCESS;
837
0
}