1 /*****************************************************************************
2 * display.c: "vout display" managment
3 *****************************************************************************
4 * Copyright (C) 2009 Laurent Aimar
7 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_video_splitter.h>
34 #include <vlc_vout_display.h>
43 /* It must be present as long as a vout_display_t must be created using a dummy
44 * vout (as an opengl provider) */
45 #define ALLOW_DUMMY_VOUT
47 static void SplitterClose(vout_display_t
*vd
);
49 /*****************************************************************************
50 * FIXME/TODO see how to have direct rendering here (interact with vout.c)
51 *****************************************************************************/
52 static picture_t
*VideoBufferNew(filter_t
*filter
)
54 vout_display_t
*vd
= (vout_display_t
*)filter
->p_owner
;
55 const video_format_t
*fmt
= &filter
->fmt_out
.video
;
57 assert(vd
->fmt
.i_chroma
== fmt
->i_chroma
&&
58 vd
->fmt
.i_width
== fmt
->i_width
&&
59 vd
->fmt
.i_height
== fmt
->i_height
);
61 picture_pool_t
*pool
= vout_display_Pool(vd
, 1);
64 return picture_pool_Get(pool
);
66 static void VideoBufferDelete(filter_t
*filter
, picture_t
*picture
)
69 picture_Release(picture
);
72 static int FilterAllocationInit(filter_t
*filter
, void *vd
)
74 filter
->pf_video_buffer_new
= VideoBufferNew
;
75 filter
->pf_video_buffer_del
= VideoBufferDelete
;
80 static void FilterAllocationClean(filter_t
*filter
)
82 filter
->pf_video_buffer_new
= NULL
;
83 filter
->pf_video_buffer_del
= NULL
;
84 filter
->p_owner
= NULL
;
87 /*****************************************************************************
89 *****************************************************************************/
92 * It creates a new vout_display_t using the given configuration.
94 static vout_display_t
*vout_display_New(vlc_object_t
*obj
,
95 const char *module
, bool load_module
,
96 const video_format_t
*fmt
,
97 const vout_display_cfg_t
*cfg
,
98 vout_display_owner_t
*owner
)
101 vout_display_t
*vd
= vlc_object_create(obj
, sizeof(*vd
));
104 video_format_Copy(&vd
->source
, fmt
);
106 /* Picture buffer does not have the concept of aspect ratio */
107 video_format_Copy(&vd
->fmt
, fmt
);
108 vd
->fmt
.i_sar_num
= 0;
109 vd
->fmt
.i_sar_den
= 0;
111 vd
->info
.is_slow
= false;
112 vd
->info
.has_double_click
= false;
113 vd
->info
.has_hide_mouse
= false;
114 vd
->info
.has_pictures_invalid
= false;
126 vlc_object_attach(vd
, obj
);
129 vd
->module
= module_need(vd
, "vout display", module
, module
&& *module
!= '\0');
131 vlc_object_release(vd
);
141 * It deletes a vout_display_t
143 static void vout_display_Delete(vout_display_t
*vd
)
146 module_unneed(vd
, vd
->module
);
148 vlc_object_release(vd
);
152 * It controls a vout_display_t
154 static int vout_display_Control(vout_display_t
*vd
, int query
, ...)
159 va_start(args
, query
);
160 result
= vd
->control(vd
, query
, args
);
165 static void vout_display_Manage(vout_display_t
*vd
)
172 void vout_display_GetDefaultDisplaySize(unsigned *width
, unsigned *height
,
173 const video_format_t
*source
,
174 const vout_display_cfg_t
*cfg
)
176 if (cfg
->display
.width
> 0 && cfg
->display
.height
> 0) {
177 *width
= cfg
->display
.width
;
178 *height
= cfg
->display
.height
;
179 } else if (cfg
->display
.width
> 0) {
180 *width
= cfg
->display
.width
;
181 *height
= (int64_t)source
->i_visible_height
* source
->i_sar_den
* cfg
->display
.width
* cfg
->display
.sar
.num
/
182 source
->i_visible_width
/ source
->i_sar_num
/ cfg
->display
.sar
.den
;
183 } else if (cfg
->display
.height
> 0) {
184 *width
= (int64_t)source
->i_visible_width
* source
->i_sar_num
* cfg
->display
.height
* cfg
->display
.sar
.den
/
185 source
->i_visible_height
/ source
->i_sar_den
/ cfg
->display
.sar
.num
;
186 *height
= cfg
->display
.height
;
187 } else if (source
->i_sar_num
>= source
->i_sar_den
) {
188 *width
= (int64_t)source
->i_visible_width
* source
->i_sar_num
* cfg
->display
.sar
.den
/ source
->i_sar_den
/ cfg
->display
.sar
.num
;
189 *height
= source
->i_visible_height
;
191 *width
= source
->i_visible_width
;
192 *height
= (int64_t)source
->i_visible_height
* source
->i_sar_den
* cfg
->display
.sar
.num
/ source
->i_sar_num
/ cfg
->display
.sar
.den
;
195 *width
= *width
* cfg
->zoom
.num
/ cfg
->zoom
.den
;
196 *height
= *height
* cfg
->zoom
.num
/ cfg
->zoom
.den
;
200 void vout_display_PlacePicture(vout_display_place_t
*place
,
201 const video_format_t
*source
,
202 const vout_display_cfg_t
*cfg
,
206 memset(place
, 0, sizeof(*place
));
207 if (cfg
->display
.width
<= 0 || cfg
->display
.height
<= 0)
211 unsigned display_width
;
212 unsigned display_height
;
214 if (cfg
->is_display_filled
) {
215 display_width
= cfg
->display
.width
;
216 display_height
= cfg
->display
.height
;
218 vout_display_cfg_t cfg_tmp
= *cfg
;
220 cfg_tmp
.display
.width
= 0;
221 cfg_tmp
.display
.height
= 0;
222 vout_display_GetDefaultDisplaySize(&display_width
, &display_height
,
226 display_width
= __MIN(display_width
, cfg
->display
.width
);
227 display_height
= __MIN(display_height
, cfg
->display
.height
);
231 const unsigned width
= source
->i_visible_width
;
232 const unsigned height
= source
->i_visible_height
;
233 /* Compute the height if we use the width to fill up display_width */
234 const int64_t scaled_height
= (int64_t)height
* display_width
* cfg
->display
.sar
.num
* source
->i_sar_den
/ width
/ source
->i_sar_num
/ cfg
->display
.sar
.den
;
235 /* And the same but switching width/height */
236 const int64_t scaled_width
= (int64_t)width
* display_height
* cfg
->display
.sar
.den
* source
->i_sar_num
/ height
/ source
->i_sar_den
/ cfg
->display
.sar
.num
;
238 /* We keep the solution that avoid filling outside the display */
239 if (scaled_width
<= cfg
->display
.width
) {
240 place
->width
= scaled_width
;
241 place
->height
= display_height
;
243 place
->width
= display_width
;
244 place
->height
= scaled_height
;
247 /* Compute position */
248 switch (cfg
->align
.horizontal
) {
249 case VOUT_DISPLAY_ALIGN_LEFT
:
252 case VOUT_DISPLAY_ALIGN_RIGHT
:
253 place
->x
= cfg
->display
.width
- place
->width
;
256 place
->x
= (cfg
->display
.width
- place
->width
) / 2;
260 switch (cfg
->align
.vertical
) {
261 case VOUT_DISPLAY_ALIGN_TOP
:
264 case VOUT_DISPLAY_ALIGN_BOTTOM
:
265 place
->y
= cfg
->display
.height
- place
->height
;
268 place
->y
= (cfg
->display
.height
- place
->height
) / 2;
273 struct vout_display_owner_sys_t
{
275 bool is_wrapper
; /* Is the current display a wrapper */
276 vout_display_t
*wrapper
; /* Vout display wrapper */
279 vout_display_cfg_t cfg
;
280 unsigned wm_state_initial
;
296 bool ch_display_filled
;
297 bool is_display_filled
;
325 video_format_t source
;
326 filter_chain_t
*filters
;
328 /* Lock protecting the variables used by
329 * VoutDisplayEvent(ie vout_display_SendEvent) */
336 mtime_t last_pressed
;
342 mtime_t double_click_timeout
;
343 mtime_t hide_timeout
;
351 bool ch_display_size
;
354 bool display_is_fullscreen
;
355 bool display_is_forced
;
359 #ifdef ALLOW_DUMMY_VOUT
360 vlc_mouse_t vout_mouse
;
364 static void DummyVoutSendDisplayEventMouse(vout_thread_t
*, vlc_mouse_t
*fallback
, const vlc_mouse_t
*m
);
366 static void VoutDisplayCreateRender(vout_display_t
*vd
)
368 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
370 osys
->filters
= NULL
;
372 video_format_t v_src
= vd
->source
;
376 video_format_t v_dst
= vd
->fmt
;
380 video_format_t v_dst_cmp
= v_dst
;
381 if ((v_src
.i_chroma
== VLC_CODEC_J420
&& v_dst
.i_chroma
== VLC_CODEC_I420
) ||
382 (v_src
.i_chroma
== VLC_CODEC_J422
&& v_dst
.i_chroma
== VLC_CODEC_I422
) ||
383 (v_src
.i_chroma
== VLC_CODEC_J440
&& v_dst
.i_chroma
== VLC_CODEC_I440
) ||
384 (v_src
.i_chroma
== VLC_CODEC_J444
&& v_dst
.i_chroma
== VLC_CODEC_I444
))
385 v_dst_cmp
.i_chroma
= v_src
.i_chroma
;
387 const bool convert
= memcmp(&v_src
, &v_dst_cmp
, sizeof(v_src
)) != 0;
391 msg_Dbg(vd
, "A filter to adapt decoder to display is needed");
393 osys
->filters
= filter_chain_New(vd
, "video filter2", false,
394 FilterAllocationInit
,
395 FilterAllocationClean
, vd
);
396 assert(osys
->filters
); /* TODO critical */
400 es_format_InitFromVideo(&src
, &v_src
);
406 for (int i
= 0; i
< 1 + (v_dst_cmp
.i_chroma
!= v_dst
.i_chroma
); i
++) {
408 es_format_InitFromVideo(&dst
, i
== 0 ? &v_dst
: &v_dst_cmp
);
410 filter_chain_Reset(osys
->filters
, &src
, &dst
);
411 filter
= filter_chain_AppendFilter(osys
->filters
,
412 NULL
, NULL
, &src
, &dst
);
418 msg_Err(vd
, "VoutDisplayCreateRender FAILED");
424 static void VoutDisplayDestroyRender(vout_display_t
*vd
)
426 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
429 filter_chain_Delete(osys
->filters
);
432 static void VoutDisplayResetRender(vout_display_t
*vd
)
434 VoutDisplayDestroyRender(vd
);
435 VoutDisplayCreateRender(vd
);
437 static void VoutDisplayEventMouse(vout_display_t
*vd
, int event
, va_list args
)
439 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
441 vlc_mutex_lock(&osys
->lock
);
444 vlc_mouse_t m
= osys
->mouse
.state
;
445 bool is_ignored
= false;
448 case VOUT_DISPLAY_EVENT_MOUSE_STATE
: {
449 const int x
= (int)va_arg(args
, int);
450 const int y
= (int)va_arg(args
, int);
451 const int button_mask
= (int)va_arg(args
, int);
456 m
.i_pressed
= button_mask
;
459 case VOUT_DISPLAY_EVENT_MOUSE_MOVED
: {
460 const int x
= (int)va_arg(args
, int);
461 const int y
= (int)va_arg(args
, int);
462 if (x
!= osys
->mouse
.state
.i_x
|| y
!= osys
->mouse
.state
.i_y
) {
463 //msg_Dbg(vd, "VoutDisplayEvent 'mouse' @%d,%d", x, y);
467 m
.b_double_click
= false;
473 case VOUT_DISPLAY_EVENT_MOUSE_PRESSED
:
474 case VOUT_DISPLAY_EVENT_MOUSE_RELEASED
: {
475 const int button
= (int)va_arg(args
, int);
476 const int button_mask
= 1 << button
;
478 /* Ignore inconsistent event */
479 if ((event
== VOUT_DISPLAY_EVENT_MOUSE_PRESSED
&& (osys
->mouse
.state
.i_pressed
& button_mask
)) ||
480 (event
== VOUT_DISPLAY_EVENT_MOUSE_RELEASED
&& !(osys
->mouse
.state
.i_pressed
& button_mask
))) {
486 msg_Dbg(vd
, "VoutDisplayEvent 'mouse button' %d t=%d", button
, event
);
488 m
.b_double_click
= false;
489 if (event
== VOUT_DISPLAY_EVENT_MOUSE_PRESSED
)
490 m
.i_pressed
|= button_mask
;
492 m
.i_pressed
&= ~button_mask
;
495 case VOUT_DISPLAY_EVENT_MOUSE_DOUBLE_CLICK
:
496 msg_Dbg(vd
, "VoutDisplayEvent 'double click'");
498 m
.b_double_click
= true;
505 vlc_mutex_unlock(&osys
->lock
);
509 /* Emulate double-click if needed */
510 if (!vd
->info
.has_double_click
&&
511 vlc_mouse_HasPressed(&osys
->mouse
.state
, &m
, MOUSE_BUTTON_LEFT
)) {
512 const mtime_t i_date
= mdate();
514 if (i_date
- osys
->mouse
.last_pressed
< osys
->mouse
.double_click_timeout
) {
515 m
.b_double_click
= true;
516 osys
->mouse
.last_pressed
= 0;
518 osys
->mouse
.last_pressed
= mdate();
523 osys
->mouse
.state
= m
;
526 osys
->mouse
.ch_activity
= true;
527 if (!vd
->info
.has_hide_mouse
)
528 osys
->mouse
.last_moved
= mdate();
531 vlc_mutex_unlock(&osys
->lock
);
534 vout_SendEventMouseVisible(osys
->vout
);
535 #ifdef ALLOW_DUMMY_VOUT
536 DummyVoutSendDisplayEventMouse(osys
->vout
, &osys
->vout_mouse
, &m
);
538 vout_SendDisplayEventMouse(osys
->vout
, &m
);
542 static void VoutDisplayEvent(vout_display_t
*vd
, int event
, va_list args
)
544 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
547 case VOUT_DISPLAY_EVENT_CLOSE
: {
548 msg_Dbg(vd
, "VoutDisplayEvent 'close'");
549 vout_SendEventClose(osys
->vout
);
552 case VOUT_DISPLAY_EVENT_KEY
: {
553 const int key
= (int)va_arg(args
, int);
554 msg_Dbg(vd
, "VoutDisplayEvent 'key' 0x%2.2x", key
);
555 vout_SendEventKey(osys
->vout
, key
);
558 case VOUT_DISPLAY_EVENT_MOUSE_STATE
:
559 case VOUT_DISPLAY_EVENT_MOUSE_MOVED
:
560 case VOUT_DISPLAY_EVENT_MOUSE_PRESSED
:
561 case VOUT_DISPLAY_EVENT_MOUSE_RELEASED
:
562 case VOUT_DISPLAY_EVENT_MOUSE_DOUBLE_CLICK
:
563 VoutDisplayEventMouse(vd
, event
, args
);
566 case VOUT_DISPLAY_EVENT_FULLSCREEN
: {
567 const int is_fullscreen
= (int)va_arg(args
, int);
569 msg_Dbg(vd
, "VoutDisplayEvent 'fullscreen' %d", is_fullscreen
);
571 vlc_mutex_lock(&osys
->lock
);
572 if (!is_fullscreen
!= !osys
->is_fullscreen
) {
573 osys
->ch_fullscreen
= true;
574 osys
->is_fullscreen
= is_fullscreen
;
576 vlc_mutex_unlock(&osys
->lock
);
580 case VOUT_DISPLAY_EVENT_WINDOW_STATE
: {
581 const unsigned state
= va_arg(args
, unsigned);
583 msg_Dbg(vd
, "VoutDisplayEvent 'window state' %u", state
);
585 vlc_mutex_lock(&osys
->lock
);
586 if (state
!= osys
->wm_state
) {
587 osys
->ch_wm_state
= true;
588 osys
->wm_state
= state
;
590 vlc_mutex_unlock(&osys
->lock
);
594 case VOUT_DISPLAY_EVENT_DISPLAY_SIZE
: {
595 const int width
= (int)va_arg(args
, int);
596 const int height
= (int)va_arg(args
, int);
597 const bool is_fullscreen
= (bool)va_arg(args
, int);
598 msg_Dbg(vd
, "VoutDisplayEvent 'resize' %dx%d %s",
599 width
, height
, is_fullscreen
? "fullscreen" : "window");
602 vlc_mutex_lock(&osys
->lock
);
604 osys
->ch_display_size
= true;
605 osys
->display_width
= width
;
606 osys
->display_height
= height
;
607 osys
->display_is_fullscreen
= is_fullscreen
;
608 osys
->display_is_forced
= false;
610 vlc_mutex_unlock(&osys
->lock
);
614 case VOUT_DISPLAY_EVENT_PICTURES_INVALID
: {
615 msg_Warn(vd
, "VoutDisplayEvent 'pictures invalid'");
618 assert(vd
->info
.has_pictures_invalid
);
620 vlc_mutex_lock(&osys
->lock
);
621 osys
->reset_pictures
= true;
622 vlc_mutex_unlock(&osys
->lock
);
626 msg_Err(vd
, "VoutDisplayEvent received event %d", event
);
627 /* TODO add an assert when all event are handled */
632 static vout_window_t
*VoutDisplayNewWindow(vout_display_t
*vd
, const vout_window_cfg_t
*cfg
)
634 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
636 return vout_NewDisplayWindow(osys
->vout
, vd
, cfg
);
638 static void VoutDisplayDelWindow(vout_display_t
*vd
, vout_window_t
*window
)
640 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
642 vout_DeleteDisplayWindow(osys
->vout
, vd
, window
);
645 static void VoutDisplayFitWindow(vout_display_t
*vd
, bool default_size
)
647 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
648 vout_display_cfg_t cfg
= osys
->cfg
;
650 if (!cfg
.is_display_filled
)
653 cfg
.display
.width
= 0;
655 cfg
.display
.height
= 0;
657 cfg
.display
.height
= osys
->height_saved
;
662 unsigned display_width
;
663 unsigned display_height
;
664 vout_display_GetDefaultDisplaySize(&display_width
, &display_height
,
667 vlc_mutex_lock(&osys
->lock
);
669 osys
->ch_display_size
= true;
670 osys
->display_width
= display_width
;
671 osys
->display_height
= display_height
;
672 osys
->display_is_fullscreen
= osys
->cfg
.is_fullscreen
;
673 osys
->display_is_forced
= true;
675 vlc_mutex_unlock(&osys
->lock
);
678 void vout_ManageDisplay(vout_display_t
*vd
, bool allow_reset_pictures
)
680 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
682 vout_display_Manage(vd
);
684 /* Handle mouse timeout */
685 const mtime_t date
= mdate();
686 bool hide_mouse
= false;
688 vlc_mutex_lock(&osys
->lock
);
690 if (!osys
->mouse
.is_hidden
&&
691 osys
->mouse
.last_moved
+ osys
->mouse
.hide_timeout
< date
) {
692 osys
->mouse
.is_hidden
= hide_mouse
= true;
693 } else if (osys
->mouse
.ch_activity
) {
694 osys
->mouse
.is_hidden
= false;
696 osys
->mouse
.ch_activity
= false;
697 vlc_mutex_unlock(&osys
->lock
);
700 if (!vd
->info
.has_hide_mouse
) {
701 msg_Dbg(vd
, "auto hidding mouse");
702 vout_display_Control(vd
, VOUT_DISPLAY_HIDE_MOUSE
);
704 vout_SendEventMouseHidden(osys
->vout
);
707 bool reset_render
= false;
710 vlc_mutex_lock(&osys
->lock
);
712 bool ch_fullscreen
= osys
->ch_fullscreen
;
713 bool is_fullscreen
= osys
->is_fullscreen
;
714 osys
->ch_fullscreen
= false;
716 bool ch_wm_state
= osys
->ch_wm_state
;
717 unsigned wm_state
= osys
->wm_state
;
718 osys
->ch_wm_state
= false;
720 bool ch_display_size
= osys
->ch_display_size
;
721 int display_width
= osys
->display_width
;
722 int display_height
= osys
->display_height
;
723 bool display_is_fullscreen
= osys
->display_is_fullscreen
;
724 bool display_is_forced
= osys
->display_is_forced
;
725 osys
->ch_display_size
= false;
728 if (allow_reset_pictures
) {
729 reset_pictures
= osys
->reset_pictures
;
730 osys
->reset_pictures
= false;
732 reset_pictures
= false;
735 vlc_mutex_unlock(&osys
->lock
);
737 if (!ch_fullscreen
&&
740 !osys
->ch_display_filled
&&
746 if (!osys
->cfg
.is_fullscreen
&& osys
->fit_window
!= 0) {
747 VoutDisplayFitWindow(vd
, osys
->fit_window
== -1);
748 osys
->fit_window
= 0;
756 vout_display_cfg_t cfg
= osys
->cfg
;
758 cfg
.is_fullscreen
= is_fullscreen
;
759 cfg
.display
.width
= cfg
.is_fullscreen
? 0 : osys
->width_saved
;
760 cfg
.display
.height
= cfg
.is_fullscreen
? 0 : osys
->height_saved
;
762 if (vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_FULLSCREEN
, &cfg
)) {
763 msg_Err(vd
, "Failed to set fullscreen");
764 is_fullscreen
= osys
->cfg
.is_fullscreen
;
766 osys
->cfg
.is_fullscreen
= is_fullscreen
;
769 vout_SendEventFullscreen(osys
->vout
, osys
->cfg
.is_fullscreen
);
773 if (ch_display_size
) {
774 vout_display_cfg_t cfg
= osys
->cfg
;
775 cfg
.display
.width
= display_width
;
776 cfg
.display
.height
= display_height
;
778 if (!cfg
.is_fullscreen
!= !display_is_fullscreen
||
779 vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_DISPLAY_SIZE
, &cfg
, display_is_forced
)) {
780 if (!cfg
.is_fullscreen
== !display_is_fullscreen
)
781 msg_Err(vd
, "Failed to resize display");
783 /* We ignore the resized */
784 display_width
= osys
->cfg
.display
.width
;
785 display_height
= osys
->cfg
.display
.height
;
787 osys
->cfg
.display
.width
= display_width
;
788 osys
->cfg
.display
.height
= display_height
;
790 if (!display_is_fullscreen
) {
791 osys
->width_saved
= display_width
;
792 osys
->height_saved
= display_height
;
796 if (osys
->ch_display_filled
) {
797 vout_display_cfg_t cfg
= osys
->cfg
;
799 cfg
.is_display_filled
= osys
->is_display_filled
;
801 if (vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_DISPLAY_FILLED
, &cfg
)) {
802 msg_Err(vd
, "Failed to change display filled state");
803 osys
->is_display_filled
= osys
->cfg
.is_display_filled
;
805 osys
->cfg
.is_display_filled
= osys
->is_display_filled
;
806 osys
->ch_display_filled
= false;
808 vout_SendEventDisplayFilled(osys
->vout
, osys
->cfg
.is_display_filled
);
812 vout_display_cfg_t cfg
= osys
->cfg
;
814 cfg
.zoom
.num
= osys
->zoom
.num
;
815 cfg
.zoom
.den
= osys
->zoom
.den
;
817 if (10 * cfg
.zoom
.num
<= cfg
.zoom
.den
) {
820 } else if (cfg
.zoom
.num
>= 10 * cfg
.zoom
.den
) {
825 if (vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_ZOOM
, &cfg
)) {
826 msg_Err(vd
, "Failed to change zoom");
827 osys
->zoom
.num
= osys
->cfg
.zoom
.num
;
828 osys
->zoom
.den
= osys
->cfg
.zoom
.den
;
830 osys
->fit_window
= -1;
833 osys
->cfg
.zoom
.num
= osys
->zoom
.num
;
834 osys
->cfg
.zoom
.den
= osys
->zoom
.den
;
835 osys
->ch_zoom
= false;
837 vout_SendEventZoom(osys
->vout
, osys
->cfg
.zoom
.num
, osys
->cfg
.zoom
.den
);
841 if (vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_WINDOW_STATE
, wm_state
)) {
842 msg_Err(vd
, "Failed to set on top");
843 wm_state
= osys
->wm_state
;
845 osys
->wm_state_initial
= wm_state
;
848 vout_SendEventOnTop(osys
->vout
, osys
->wm_state_initial
);
852 video_format_t source
= vd
->source
;
854 if (osys
->sar
.num
> 0 && osys
->sar
.den
> 0) {
855 source
.i_sar_num
= osys
->sar
.num
;
856 source
.i_sar_den
= osys
->sar
.den
;
858 source
.i_sar_num
= osys
->source
.i_sar_num
;
859 source
.i_sar_den
= osys
->source
.i_sar_den
;
862 if (vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_SOURCE_ASPECT
, &source
)) {
863 /* There nothing much we can do. The only reason a vout display
864 * does not support it is because it need the core to add black border
865 * to the video for it.
866 * TODO add black borders ?
868 msg_Err(vd
, "Failed to change source AR");
870 } else if (!osys
->fit_window
) {
871 osys
->fit_window
= 1;
874 osys
->sar
.num
= source
.i_sar_num
;
875 osys
->sar
.den
= source
.i_sar_den
;
876 osys
->ch_sar
= false;
879 if (osys
->sar
.num
== osys
->source
.i_sar_num
&&
880 osys
->sar
.den
== osys
->source
.i_sar_den
)
882 vout_SendEventSourceAspect(osys
->vout
, 0, 0);
886 unsigned dar_num
, dar_den
;
887 vlc_ureduce( &dar_num
, &dar_den
,
888 osys
->sar
.num
* vd
->source
.i_visible_width
,
889 osys
->sar
.den
* vd
->source
.i_visible_height
,
891 vout_SendEventSourceAspect(osys
->vout
, dar_num
, dar_den
);
896 video_format_t source
= vd
->source
;
897 unsigned crop_num
= osys
->crop
.num
;
898 unsigned crop_den
= osys
->crop
.den
;
900 source
.i_x_offset
= osys
->crop
.x
;
901 source
.i_y_offset
= osys
->crop
.y
;
902 source
.i_visible_width
= osys
->crop
.width
;
903 source
.i_visible_height
= osys
->crop
.height
;
906 const bool is_valid
= source
.i_x_offset
< source
.i_width
&&
907 source
.i_y_offset
< source
.i_height
&&
908 source
.i_x_offset
+ source
.i_visible_width
<= source
.i_width
&&
909 source
.i_y_offset
+ source
.i_visible_height
<= source
.i_height
&&
910 source
.i_visible_width
> 0 && source
.i_visible_height
> 0;
912 if (!is_valid
|| vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_SOURCE_CROP
, &source
)) {
914 msg_Err(vd
, "Failed to change source crop TODO implement crop at core");
916 msg_Err(vd
, "Invalid crop requested");
919 crop_num
= osys
->crop_saved
.num
;
920 crop_den
= osys
->crop_saved
.den
;
921 /* FIXME implement cropping in the core if not supported by the
924 } else if (!osys
->fit_window
) {
925 osys
->fit_window
= 1;
928 osys
->crop
.x
= source
.i_x_offset
;
929 osys
->crop
.y
= source
.i_y_offset
;
930 osys
->crop
.width
= source
.i_visible_width
;
931 osys
->crop
.height
= source
.i_visible_height
;
932 osys
->crop
.num
= crop_num
;
933 osys
->crop
.den
= crop_den
;
934 osys
->ch_crop
= false;
936 /* TODO fix when a ratio is used (complicated). */
937 const unsigned left
= osys
->crop
.x
- osys
->source
.i_x_offset
;
938 const unsigned top
= osys
->crop
.y
- osys
->source
.i_y_offset
;
939 const unsigned right
= osys
->source
.i_visible_width
- (osys
->crop
.width
+ osys
->crop
.x
);
940 const unsigned bottom
= osys
->source
.i_visible_height
- (osys
->crop
.height
+ osys
->crop
.y
);
941 vout_SendEventSourceCrop(osys
->vout
,
942 osys
->crop
.num
, osys
->crop
.den
,
943 left
, top
, right
, bottom
);
947 if (reset_pictures
) {
948 if (vout_display_Control(vd
, VOUT_DISPLAY_RESET_PICTURES
)) {
949 /* FIXME what to do here ? */
950 msg_Err(vd
, "Failed to reset pictures (probably fatal)");
956 VoutDisplayResetRender(vd
);
959 bool vout_AreDisplayPicturesInvalid(vout_display_t
*vd
)
961 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
963 vlc_mutex_lock(&osys
->lock
);
964 const bool reset_pictures
= osys
->reset_pictures
;
965 vlc_mutex_unlock(&osys
->lock
);
967 return reset_pictures
;
970 bool vout_IsDisplayFiltered(vout_display_t
*vd
)
972 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
974 return osys
->filters
!= NULL
;
977 picture_t
*vout_FilterDisplay(vout_display_t
*vd
, picture_t
*picture
)
979 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
981 assert(osys
->filters
);
982 return filter_chain_VideoFilter(osys
->filters
, picture
);
985 void vout_SetDisplayFullscreen(vout_display_t
*vd
, bool is_fullscreen
)
987 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
989 vlc_mutex_lock(&osys
->lock
);
990 if (!osys
->is_fullscreen
!= !is_fullscreen
) {
991 osys
->ch_fullscreen
= true;
992 osys
->is_fullscreen
= is_fullscreen
;
994 vlc_mutex_unlock(&osys
->lock
);
997 void vout_SetDisplayFilled(vout_display_t
*vd
, bool is_filled
)
999 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1001 if (!osys
->is_display_filled
!= !is_filled
) {
1002 osys
->ch_display_filled
= true;
1003 osys
->is_display_filled
= is_filled
;
1007 void vout_SetDisplayZoom(vout_display_t
*vd
, int num
, int den
)
1009 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1011 if (osys
->is_display_filled
||
1012 osys
->zoom
.num
!= num
|| osys
->zoom
.den
!= den
) {
1013 osys
->ch_zoom
= true;
1014 osys
->zoom
.num
= num
;
1015 osys
->zoom
.den
= den
;
1019 void vout_SetWindowState(vout_display_t
*vd
, unsigned state
)
1021 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1023 vlc_mutex_lock(&osys
->lock
);
1024 if (osys
->wm_state
!= state
) {
1025 osys
->ch_wm_state
= true;
1026 osys
->wm_state
= state
;
1028 vlc_mutex_unlock(&osys
->lock
);
1031 void vout_SetDisplayAspect(vout_display_t
*vd
, unsigned sar_num
, unsigned sar_den
)
1033 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1035 if (osys
->sar
.num
!= sar_num
|| osys
->sar
.den
!= sar_den
) {
1036 osys
->ch_sar
= true;
1037 osys
->sar
.num
= sar_num
;
1038 osys
->sar
.den
= sar_den
;
1041 void vout_SetDisplayCrop(vout_display_t
*vd
,
1042 unsigned crop_num
, unsigned crop_den
,
1043 unsigned x
, unsigned y
, unsigned width
, unsigned height
)
1045 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1047 if (osys
->crop
.x
!= x
|| osys
->crop
.y
!= y
||
1048 osys
->crop
.width
!= width
|| osys
->crop
.height
!= height
) {
1052 osys
->crop
.width
= width
;
1053 osys
->crop
.height
= height
;
1054 osys
->crop
.num
= crop_num
;
1055 osys
->crop
.den
= crop_den
;
1057 osys
->ch_crop
= true;
1060 vout_opengl_t
*vout_GetDisplayOpengl(vout_display_t
*vd
)
1063 if (vout_display_Control(vd
, VOUT_DISPLAY_GET_OPENGL
, &gl
))
1068 static vout_display_t
*DisplayNew(vout_thread_t
*vout
,
1069 const video_format_t
*source_org
,
1070 const vout_display_state_t
*state
,
1072 bool is_wrapper
, vout_display_t
*wrapper
,
1073 mtime_t double_click_timeout
,
1074 mtime_t hide_timeout
,
1075 const vout_display_owner_t
*owner_ptr
)
1078 vout_display_owner_sys_t
*osys
= calloc(1, sizeof(*osys
));
1079 vout_display_cfg_t
*cfg
= &osys
->cfg
;
1082 osys
->wm_state_initial
= VOUT_WINDOW_STATE_NORMAL
;
1083 osys
->sar_initial
.num
= state
->sar
.num
;
1084 osys
->sar_initial
.den
= state
->sar
.den
;
1085 vout_display_GetDefaultDisplaySize(&cfg
->display
.width
, &cfg
->display
.height
,
1089 osys
->is_wrapper
= is_wrapper
;
1090 osys
->wrapper
= wrapper
;
1092 vlc_mutex_init(&osys
->lock
);
1094 vlc_mouse_Init(&osys
->mouse
.state
);
1095 osys
->mouse
.last_moved
= mdate();
1096 osys
->mouse
.double_click_timeout
= double_click_timeout
;
1097 osys
->mouse
.hide_timeout
= hide_timeout
;
1098 osys
->is_fullscreen
= cfg
->is_fullscreen
;
1100 osys
->display_width
= cfg
->display
.width
;
1101 osys
->height_saved
=
1102 osys
->display_height
= cfg
->display
.height
;
1103 osys
->is_display_filled
= cfg
->is_display_filled
;
1104 osys
->zoom
.num
= cfg
->zoom
.num
;
1105 osys
->zoom
.den
= cfg
->zoom
.den
;
1106 osys
->wm_state
= state
->is_on_top
? VOUT_WINDOW_STATE_ABOVE
1107 : VOUT_WINDOW_STATE_NORMAL
;
1108 osys
->fit_window
= 0;
1110 osys
->source
= *source_org
;
1112 video_format_t source
= *source_org
;
1118 source
.i_visible_width
=
1119 osys
->crop
.width
= source
.i_width
;
1120 source
.i_visible_height
=
1121 osys
->crop
.height
= source
.i_height
;
1122 osys
->crop_saved
.num
= 0;
1123 osys
->crop_saved
.den
= 0;
1127 osys
->sar
.num
= osys
->sar_initial
.num
? osys
->sar_initial
.num
: source
.i_sar_num
;
1128 osys
->sar
.den
= osys
->sar_initial
.den
? osys
->sar_initial
.den
: source
.i_sar_den
;
1129 #ifdef ALLOW_DUMMY_VOUT
1130 vlc_mouse_Init(&osys
->vout_mouse
);
1133 vout_display_owner_t owner
;
1137 owner
.event
= VoutDisplayEvent
;
1138 owner
.window_new
= VoutDisplayNewWindow
;
1139 owner
.window_del
= VoutDisplayDelWindow
;
1144 vout_display_t
*p_display
= vout_display_New(VLC_OBJECT(vout
),
1145 module
, !is_wrapper
,
1146 &source
, cfg
, &owner
);
1152 VoutDisplayCreateRender(p_display
);
1154 /* Setup delayed request */
1155 if (osys
->sar
.num
!= source_org
->i_sar_num
||
1156 osys
->sar
.den
!= source_org
->i_sar_den
)
1157 osys
->ch_sar
= true;
1158 if (osys
->wm_state
!= osys
->wm_state_initial
)
1159 osys
->ch_wm_state
= true;
1160 if (osys
->crop
.x
!= source_org
->i_x_offset
||
1161 osys
->crop
.y
!= source_org
->i_y_offset
||
1162 osys
->crop
.width
!= source_org
->i_visible_width
||
1163 osys
->crop
.height
!= source_org
->i_visible_height
)
1164 osys
->ch_crop
= true;
1169 void vout_DeleteDisplay(vout_display_t
*vd
, vout_display_state_t
*state
)
1171 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1174 if (!osys
->is_wrapper
)
1175 state
->cfg
= osys
->cfg
;
1176 state
->is_on_top
= (osys
->wm_state
& VOUT_WINDOW_STATE_ABOVE
) != 0;
1177 state
->sar
.num
= osys
->sar_initial
.num
;
1178 state
->sar
.den
= osys
->sar_initial
.den
;
1181 VoutDisplayDestroyRender(vd
);
1182 if (osys
->is_wrapper
)
1184 vout_display_Delete(vd
);
1185 vlc_mutex_destroy(&osys
->lock
);
1189 /*****************************************************************************
1191 *****************************************************************************/
1192 vout_display_t
*vout_NewDisplay(vout_thread_t
*vout
,
1193 const video_format_t
*source
,
1194 const vout_display_state_t
*state
,
1196 mtime_t double_click_timeout
,
1197 mtime_t hide_timeout
)
1199 return DisplayNew(vout
, source
, state
, module
, false, NULL
,
1200 double_click_timeout
, hide_timeout
, NULL
);
1203 static void SplitterClose(vout_display_t
*vd
)
1210 /*****************************************************************************
1212 *****************************************************************************/
1213 struct vout_display_sys_t
{
1214 video_splitter_t
*splitter
;
1218 picture_t
**picture
;
1219 vout_display_t
**display
;
1221 struct video_splitter_owner_t
{
1222 vout_display_t
*wrapper
;
1225 static vout_window_t
*SplitterNewWindow(vout_display_t
*vd
, const vout_window_cfg_t
*cfg_ptr
)
1227 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1229 vout_window_cfg_t cfg
= *cfg_ptr
;
1230 cfg
.is_standalone
= true;
1231 cfg
.x
+= 0;//output->window.i_x; FIXME
1232 cfg
.y
+= 0;//output->window.i_y;
1234 return vout_NewDisplayWindow(osys
->vout
, vd
, &cfg
);
1236 static void SplitterDelWindow(vout_display_t
*vd
, vout_window_t
*window
)
1238 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1240 vout_DeleteDisplayWindow(osys
->vout
, vd
, window
);
1242 static void SplitterEvent(vout_display_t
*vd
, int event
, va_list args
)
1244 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1248 case VOUT_DISPLAY_EVENT_MOUSE_STATE
:
1249 case VOUT_DISPLAY_EVENT_MOUSE_MOVED
:
1250 case VOUT_DISPLAY_EVENT_MOUSE_PRESSED
:
1251 case VOUT_DISPLAY_EVENT_MOUSE_RELEASED
:
1255 case VOUT_DISPLAY_EVENT_MOUSE_DOUBLE_CLICK
:
1256 case VOUT_DISPLAY_EVENT_KEY
:
1257 case VOUT_DISPLAY_EVENT_CLOSE
:
1258 case VOUT_DISPLAY_EVENT_FULLSCREEN
:
1259 case VOUT_DISPLAY_EVENT_DISPLAY_SIZE
:
1260 case VOUT_DISPLAY_EVENT_PICTURES_INVALID
:
1261 VoutDisplayEvent(vd
, event
, args
);
1265 msg_Err(vd
, "SplitterEvent TODO");
1270 static picture_t
*SplitterGet(vout_display_t
*vd
)
1273 return picture_NewFromFormat(&vd
->fmt
);
1275 static void SplitterPrepare(vout_display_t
*vd
, picture_t
*picture
)
1277 vout_display_sys_t
*sys
= vd
->sys
;
1279 picture_Hold(picture
);
1281 if (video_splitter_Filter(sys
->splitter
, sys
->picture
, picture
)) {
1282 for (int i
= 0; i
< sys
->count
; i
++)
1283 sys
->picture
[i
] = NULL
;
1284 picture_Release(picture
);
1288 for (int i
= 0; i
< sys
->count
; i
++) {
1290 /* FIXME now vout_FilterDisplay already return a direct buffer FIXME */
1291 sys
->picture
[i
] = vout_FilterDisplay(sys
->display
[i
], sys
->picture
[i
]);
1292 if (!sys
->picture
[i
])
1296 picture_t
*direct
= vout_display_Get(sys
->display
[i
]);
1298 msg_Err(vd
, "Failed to get a direct buffer");
1299 picture_Release(sys
->picture
[i
]);
1300 sys
->picture
[i
] = NULL
;
1304 /* FIXME not always needed (easy when there is a osys->filters) */
1305 picture_Copy(direct
, sys
->picture
[i
]);
1306 picture_Release(sys
->picture
[i
]);
1307 sys
->picture
[i
] = direct
;
1309 vout_display_Prepare(sys
->display
[i
], sys
->picture
[i
]);
1312 static void SplitterDisplay(vout_display_t
*vd
, picture_t
*picture
)
1314 vout_display_sys_t
*sys
= vd
->sys
;
1316 for (int i
= 0; i
< sys
->count
; i
++) {
1317 if (sys
->picture
[i
])
1318 vout_display_Display(sys
->display
[i
], sys
->picture
[i
]);
1320 picture_Release(picture
);
1322 static int SplitterControl(vout_display_t
*vd
, int query
, va_list args
)
1324 return VLC_EGENERIC
;
1326 static void SplitterManage(vout_display_t
*vd
)
1328 vout_display_sys_t
*sys
= vd
->sys
;
1330 for (int i
= 0; i
< sys
->count
; i
++)
1331 vout_ManageDisplay(sys
->display
[i
]);
1334 static int SplitterPictureNew(video_splitter_t
*splitter
, picture_t
*picture
[])
1336 vout_display_sys_t
*wsys
= splitter
->p_owner
->wrapper
->sys
;
1338 for (int i
= 0; i
< wsys
->count
; i
++) {
1340 picture
[i
] = picture_NewFromFormat(&wsys
->display
[i
]->source
);
1342 for (int j
= 0; j
< i
; j
++)
1343 picture_Release(picture
[j
]);
1344 return VLC_EGENERIC
;
1349 static void SplitterPictureDel(video_splitter_t
*splitter
, picture_t
*picture
[])
1351 vout_display_sys_t
*wsys
= splitter
->p_owner
->wrapper
->sys
;
1353 for (int i
= 0; i
< wsys
->count
; i
++)
1354 picture_Release(picture
[i
]);
1356 static void SplitterClose(vout_display_t
*vd
)
1358 vout_display_sys_t
*sys
= vd
->sys
;
1361 video_splitter_t
*splitter
= sys
->splitter
;
1362 free(splitter
->p_owner
);
1363 video_splitter_Delete(splitter
);
1366 for (int i
= 0; i
< sys
->count
; i
++)
1367 vout_DeleteDisplay(sys
->display
[i
], NULL
);
1368 TAB_CLEAN(sys
->count
, sys
->display
);
1374 vout_display_t
*vout_NewSplitter(vout_thread_t
*vout
,
1375 const video_format_t
*source
,
1376 const vout_display_state_t
*state
,
1378 const char *splitter_module
,
1379 mtime_t double_click_timeout
,
1380 mtime_t hide_timeout
)
1382 video_splitter_t
*splitter
=
1383 video_splitter_New(VLC_OBJECT(vout
), splitter_module
, source
);
1388 vout_display_t
*wrapper
=
1389 DisplayNew(vout
, source
, state
, module
, true, NULL
,
1390 double_click_timeout
, hide_timeout
, NULL
);
1392 video_splitter_Delete(splitter
);
1395 vout_display_sys_t
*sys
= malloc(sizeof(*sys
));
1398 sys
->picture
= calloc(splitter
->i_output
, sizeof(*sys
->picture
));
1401 sys
->splitter
= splitter
;
1403 wrapper
->get
= SplitterGet
;
1404 wrapper
->prepare
= SplitterPrepare
;
1405 wrapper
->display
= SplitterDisplay
;
1406 wrapper
->control
= SplitterControl
;
1407 wrapper
->manage
= SplitterManage
;
1411 video_splitter_owner_t
*owner
= malloc(sizeof(*owner
));
1414 owner
->wrapper
= wrapper
;
1415 splitter
->p_owner
= owner
;
1416 splitter
->pf_picture_new
= SplitterPictureNew
;
1417 splitter
->pf_picture_del
= SplitterPictureDel
;
1420 TAB_INIT(sys
->count
, sys
->display
);
1421 for (int i
= 0; i
< splitter
->i_output
; i
++) {
1422 vout_display_owner_t owner
;
1424 owner
.event
= SplitterEvent
;
1425 owner
.window_new
= SplitterNewWindow
;
1426 owner
.window_del
= SplitterDelWindow
;
1428 const video_splitter_output_t
*output
= &splitter
->p_output
[i
];
1429 vout_display_state_t ostate
;
1431 memset(&ostate
, 0, sizeof(ostate
));
1432 ostate
.cfg
.is_fullscreen
= false;
1433 ostate
.cfg
.display
= state
->cfg
.display
;
1434 ostate
.cfg
.align
.horizontal
= 0; /* TODO */
1435 ostate
.cfg
.align
.vertical
= 0; /* TODO */
1436 ostate
.cfg
.is_display_filled
= true;
1437 ostate
.cfg
.zoom
.num
= 1;
1438 ostate
.cfg
.zoom
.den
= 1;
1440 vout_display_t
*vd
= DisplayNew(vout
, &output
->fmt
, &ostate
,
1441 output
->psz_module
? output
->psz_module
: module
,
1443 double_click_timeout
, hide_timeout
, &owner
);
1445 vout_DeleteDisplay(wrapper
, NULL
);
1448 TAB_APPEND(sys
->count
, sys
->display
, vd
);
1455 /*****************************************************************************
1457 *****************************************************************************/
1458 #include "vout_internal.h"
1459 void vout_SendDisplayEventMouse(vout_thread_t
*vout
, const vlc_mouse_t
*m
)
1461 if (vlc_mouse_HasMoved(&vout
->p
->mouse
, m
)) {
1462 vout_SendEventMouseMoved(vout
, m
->i_x
, m
->i_y
);
1464 if (vlc_mouse_HasButton(&vout
->p
->mouse
, m
)) {
1465 static const int buttons
[] = {
1467 MOUSE_BUTTON_CENTER
,
1469 MOUSE_BUTTON_WHEEL_UP
,
1470 MOUSE_BUTTON_WHEEL_DOWN
,
1473 for (int i
= 0; buttons
[i
] >= 0; i
++) {
1474 const int button
= buttons
[i
];
1475 if (vlc_mouse_HasPressed(&vout
->p
->mouse
, m
, button
))
1476 vout_SendEventMousePressed(vout
, button
);
1477 else if (vlc_mouse_HasReleased(&vout
->p
->mouse
, m
, button
))
1478 vout_SendEventMouseReleased(vout
, button
);
1481 if (m
->b_double_click
)
1482 vout_SendEventMouseDoubleClick(vout
);
1483 vout
->p
->mouse
= *m
;
1485 #ifdef ALLOW_DUMMY_VOUT
1486 static void DummyVoutSendDisplayEventMouse(vout_thread_t
*vout
, vlc_mouse_t
*fallback
, const vlc_mouse_t
*m
)
1488 vout_thread_sys_t p
;
1491 p
.mouse
= *fallback
;
1494 vout_SendDisplayEventMouse(vout
, m
);
1495 if (vout
->p
== &p
) {
1496 *fallback
= p
.mouse
;
1501 vout_window_t
* vout_NewDisplayWindow(vout_thread_t
*vout
, vout_display_t
*vd
, const vout_window_cfg_t
*cfg
)
1504 vout_window_cfg_t cfg_override
= *cfg
;
1506 if( !var_InheritBool( vout
, "embedded-video" ) )
1507 cfg_override
.is_standalone
= true;
1509 return vout_window_New(VLC_OBJECT(vout
), NULL
, &cfg_override
);
1511 void vout_DeleteDisplayWindow(vout_thread_t
*vout
, vout_display_t
*vd
, vout_window_t
*window
)
1515 vout_window_Delete(window
);