/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 | } |