1 /*****************************************************************************
2 * display.c: "vout display" management
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 it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * 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>
36 #include <vlc_block.h>
37 #include <vlc_modules.h>
38 #include <vlc_filter.h>
39 #include <vlc_picture_pool.h>
48 static void SplitterClose(vout_display_t
*vd
);
50 /*****************************************************************************
51 * FIXME/TODO see how to have direct rendering here (interact with vout.c)
52 *****************************************************************************/
53 static picture_t
*VideoBufferNew(filter_t
*filter
)
55 vout_display_t
*vd
= filter
->owner
.sys
;
56 const video_format_t
*fmt
= &filter
->fmt_out
.video
;
58 assert(vd
->fmt
.i_chroma
== fmt
->i_chroma
&&
59 vd
->fmt
.i_width
== fmt
->i_width
&&
60 vd
->fmt
.i_height
== fmt
->i_height
);
62 picture_pool_t
*pool
= vout_display_Pool(vd
, 3);
65 return picture_pool_Get(pool
);
68 /*****************************************************************************
70 *****************************************************************************/
73 * It creates a new vout_display_t using the given configuration.
75 static vout_display_t
*vout_display_New(vlc_object_t
*obj
,
76 const char *module
, bool load_module
,
77 const video_format_t
*fmt
,
78 const vout_display_cfg_t
*cfg
,
79 vout_display_owner_t
*owner
)
82 vout_display_t
*vd
= vlc_custom_create(obj
, sizeof(*vd
), "vout display" );
85 video_format_Copy(&vd
->source
, fmt
);
87 /* Picture buffer does not have the concept of aspect ratio */
88 video_format_Copy(&vd
->fmt
, fmt
);
89 vd
->fmt
.i_sar_num
= 0;
90 vd
->fmt
.i_sar_den
= 0;
92 vd
->info
.is_slow
= false;
93 vd
->info
.has_double_click
= false;
94 vd
->info
.needs_hide_mouse
= false;
95 vd
->info
.has_pictures_invalid
= false;
96 vd
->info
.subpicture_chromas
= NULL
;
109 vd
->module
= module_need(vd
, "vout display", module
, module
&& *module
!= '\0');
111 vlc_object_release(vd
);
121 * It deletes a vout_display_t
123 static void vout_display_Delete(vout_display_t
*vd
)
126 module_unneed(vd
, vd
->module
);
128 video_format_Clean(&vd
->source
);
129 video_format_Clean(&vd
->fmt
);
131 vlc_object_release(vd
);
135 * It controls a vout_display_t
137 static int vout_display_Control(vout_display_t
*vd
, int query
, ...)
142 va_start(args
, query
);
143 result
= vd
->control(vd
, query
, args
);
149 static void vout_display_Manage(vout_display_t
*vd
)
156 void vout_display_GetDefaultDisplaySize(unsigned *width
, unsigned *height
,
157 const video_format_t
*source
,
158 const vout_display_cfg_t
*cfg
)
160 if (cfg
->display
.width
!= 0 && cfg
->display
.height
!= 0) {
161 *width
= cfg
->display
.width
;
162 *height
= cfg
->display
.height
;
163 } else if (cfg
->display
.width
!= 0) {
164 *width
= cfg
->display
.width
;
165 *height
= (int64_t)source
->i_visible_height
* source
->i_sar_den
* cfg
->display
.width
* cfg
->display
.sar
.num
/
166 source
->i_visible_width
/ source
->i_sar_num
/ cfg
->display
.sar
.den
;
167 } else if (cfg
->display
.height
!= 0) {
168 *width
= (int64_t)source
->i_visible_width
* source
->i_sar_num
* cfg
->display
.height
* cfg
->display
.sar
.den
/
169 source
->i_visible_height
/ source
->i_sar_den
/ cfg
->display
.sar
.num
;
170 *height
= cfg
->display
.height
;
171 } else if (source
->i_sar_num
>= source
->i_sar_den
) {
172 *width
= (int64_t)source
->i_visible_width
* source
->i_sar_num
* cfg
->display
.sar
.den
/ source
->i_sar_den
/ cfg
->display
.sar
.num
;
173 *height
= source
->i_visible_height
;
175 *width
= source
->i_visible_width
;
176 *height
= (int64_t)source
->i_visible_height
* source
->i_sar_den
* cfg
->display
.sar
.num
/ source
->i_sar_num
/ cfg
->display
.sar
.den
;
179 *width
= *width
* cfg
->zoom
.num
/ cfg
->zoom
.den
;
180 *height
= *height
* cfg
->zoom
.num
/ cfg
->zoom
.den
;
182 if (ORIENT_IS_SWAP(source
->orientation
)) {
184 unsigned store
= *width
;
191 void vout_display_PlacePicture(vout_display_place_t
*place
,
192 const video_format_t
*source
,
193 const vout_display_cfg_t
*cfg
,
197 memset(place
, 0, sizeof(*place
));
198 if (cfg
->display
.width
== 0 || cfg
->display
.height
== 0)
202 unsigned display_width
;
203 unsigned display_height
;
205 video_format_t source_rot
;
206 video_format_ApplyRotation(&source_rot
, source
);
207 source
= &source_rot
;
209 if (cfg
->is_display_filled
) {
210 display_width
= cfg
->display
.width
;
211 display_height
= cfg
->display
.height
;
213 vout_display_cfg_t cfg_tmp
= *cfg
;
215 cfg_tmp
.display
.width
= 0;
216 cfg_tmp
.display
.height
= 0;
217 vout_display_GetDefaultDisplaySize(&display_width
, &display_height
,
221 display_width
= __MIN(display_width
, cfg
->display
.width
);
222 display_height
= __MIN(display_height
, cfg
->display
.height
);
226 const unsigned width
= source
->i_visible_width
;
227 const unsigned height
= source
->i_visible_height
;
228 /* Compute the height if we use the width to fill up display_width */
229 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
);
230 /* And the same but switching width/height */
231 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
);
233 if (source
->projection_mode
== PROJECTION_MODE_RECTANGULAR
) {
234 /* We keep the solution that avoid filling outside the display */
235 if (scaled_width
<= cfg
->display
.width
) {
236 place
->width
= scaled_width
;
237 place
->height
= display_height
;
239 place
->width
= display_width
;
240 place
->height
= scaled_height
;
243 /* No need to preserve an aspect ratio for 360 video.
244 * They can fill the display. */
245 place
->width
= display_width
;
246 place
->height
= display_height
;
249 /* Compute position */
250 switch (cfg
->align
.horizontal
) {
251 case VOUT_DISPLAY_ALIGN_LEFT
:
254 case VOUT_DISPLAY_ALIGN_RIGHT
:
255 place
->x
= cfg
->display
.width
- place
->width
;
258 place
->x
= ((int)cfg
->display
.width
- (int)place
->width
) / 2;
262 switch (cfg
->align
.vertical
) {
263 case VOUT_DISPLAY_ALIGN_TOP
:
266 case VOUT_DISPLAY_ALIGN_BOTTOM
:
267 place
->y
= cfg
->display
.height
- place
->height
;
270 place
->y
= ((int)cfg
->display
.height
- (int)place
->height
) / 2;
275 void vout_display_SendMouseMovedDisplayCoordinates(vout_display_t
*vd
, video_orientation_t orient_display
, int m_x
, int m_y
, vout_display_place_t
*place
)
277 video_format_t source_rot
= vd
->source
;
278 video_format_TransformTo(&source_rot
, orient_display
);
280 if (place
->width
> 0 && place
->height
> 0) {
282 int x
= (int)(source_rot
.i_x_offset
+
283 (int64_t)(m_x
- place
->x
) * source_rot
.i_visible_width
/ place
->width
);
284 int y
= (int)(source_rot
.i_y_offset
+
285 (int64_t)(m_y
- place
->y
) * source_rot
.i_visible_height
/ place
->height
);
287 video_transform_t transform
= video_format_GetTransform(vd
->source
.orientation
, orient_display
);
296 y
= vd
->source
.i_visible_height
- store
;
299 x
= vd
->source
.i_visible_width
- x
;
300 y
= vd
->source
.i_visible_height
- y
;
304 x
= vd
->source
.i_visible_width
- y
;
307 case TRANSFORM_HFLIP
:
308 x
= vd
->source
.i_visible_width
- x
;
310 case TRANSFORM_VFLIP
:
311 y
= vd
->source
.i_visible_height
- y
;
313 case TRANSFORM_TRANSPOSE
:
318 case TRANSFORM_ANTI_TRANSPOSE
:
320 x
= vd
->source
.i_visible_width
- y
;
321 y
= vd
->source
.i_visible_height
- store
;
327 vout_display_SendEventMouseMoved (vd
, x
, y
);
333 bool is_splitter
; /* Is this a video splitter */
336 vout_display_cfg_t cfg
;
337 vlc_rational_t sar_initial
;
340 bool is_display_filled
;
344 #if defined(_WIN32) || defined(__OS2__)
345 unsigned width_saved
;
346 unsigned height_saved
;
349 bool window_fullscreen
;
352 unsigned wm_state_initial
;
368 vlc_viewpoint_t viewpoint
;
369 vlc_viewpoint_t display_viewpoint
;
372 video_format_t source
;
373 filter_chain_t
*filters
;
375 /* Lock protecting the variables used by
376 * VoutDisplayEvent(ie vout_display_SendEvent) */
383 mtime_t last_pressed
;
389 mtime_t double_click_timeout
;
390 mtime_t hide_timeout
;
395 signed char fit_window
;
397 bool ch_display_size
;
400 } vout_display_owner_sys_t
;
402 static int VoutDisplayCreateRender(vout_display_t
*vd
)
404 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
405 filter_owner_t owner
= {
408 .buffer_new
= VideoBufferNew
,
412 osys
->filters
= filter_chain_NewVideo(vd
, false, &owner
);
413 if (unlikely(osys
->filters
== NULL
))
416 video_format_t v_src
= vd
->source
;
420 video_format_t v_dst
= vd
->fmt
;
424 video_format_t v_dst_cmp
= v_dst
;
425 if ((v_src
.i_chroma
== VLC_CODEC_J420
&& v_dst
.i_chroma
== VLC_CODEC_I420
) ||
426 (v_src
.i_chroma
== VLC_CODEC_J422
&& v_dst
.i_chroma
== VLC_CODEC_I422
) ||
427 (v_src
.i_chroma
== VLC_CODEC_J440
&& v_dst
.i_chroma
== VLC_CODEC_I440
) ||
428 (v_src
.i_chroma
== VLC_CODEC_J444
&& v_dst
.i_chroma
== VLC_CODEC_I444
))
429 v_dst_cmp
.i_chroma
= v_src
.i_chroma
;
431 const bool convert
= memcmp(&v_src
, &v_dst_cmp
, sizeof(v_src
)) != 0;
435 msg_Dbg(vd
, "A filter to adapt decoder %4.4s to display %4.4s is needed",
436 (const char *)&v_src
.i_chroma
, (const char *)&v_dst
.i_chroma
);
440 es_format_InitFromVideo(&src
, &v_src
);
445 for (int i
= 0; i
< 1 + (v_dst_cmp
.i_chroma
!= v_dst
.i_chroma
); i
++) {
448 es_format_InitFromVideo(&dst
, i
== 0 ? &v_dst
: &v_dst_cmp
);
450 filter_chain_Reset(osys
->filters
, &src
, &dst
);
451 ret
= filter_chain_AppendConverter(osys
->filters
, &src
, &dst
);
452 es_format_Clean(&dst
);
456 es_format_Clean(&src
);
459 msg_Err(vd
, "Failed to adapt decoder format to display");
460 filter_chain_Delete(osys
->filters
);
461 osys
->filters
= NULL
;
466 static void VoutDisplayDestroyRender(vout_display_t
*vd
)
468 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
471 filter_chain_Delete(osys
->filters
);
474 static int VoutDisplayResetRender(vout_display_t
*vd
)
476 VoutDisplayDestroyRender(vd
);
477 return VoutDisplayCreateRender(vd
);
480 static void VoutDisplayEventMouse(vout_display_t
*vd
, int event
, va_list args
)
482 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
484 vlc_mutex_lock(&osys
->lock
);
487 vlc_mouse_t m
= osys
->mouse
.state
;
488 bool is_ignored
= false;
491 case VOUT_DISPLAY_EVENT_MOUSE_STATE
: {
492 const int x
= (int)va_arg(args
, int);
493 const int y
= (int)va_arg(args
, int);
494 const int button_mask
= (int)va_arg(args
, int);
499 m
.i_pressed
= button_mask
;
502 case VOUT_DISPLAY_EVENT_MOUSE_MOVED
: {
503 const int x
= (int)va_arg(args
, int);
504 const int y
= (int)va_arg(args
, int);
506 //msg_Dbg(vd, "VoutDisplayEvent 'mouse' @%d,%d", x, y);
510 m
.b_double_click
= false;
513 case VOUT_DISPLAY_EVENT_MOUSE_PRESSED
:
514 case VOUT_DISPLAY_EVENT_MOUSE_RELEASED
: {
515 const int button
= (int)va_arg(args
, int);
516 const int button_mask
= 1 << button
;
518 /* Ignore inconsistent event */
519 if ((event
== VOUT_DISPLAY_EVENT_MOUSE_PRESSED
&& (osys
->mouse
.state
.i_pressed
& button_mask
)) ||
520 (event
== VOUT_DISPLAY_EVENT_MOUSE_RELEASED
&& !(osys
->mouse
.state
.i_pressed
& button_mask
))) {
526 msg_Dbg(vd
, "VoutDisplayEvent 'mouse button' %d t=%d", button
, event
);
528 m
.b_double_click
= false;
529 if (event
== VOUT_DISPLAY_EVENT_MOUSE_PRESSED
)
530 m
.i_pressed
|= button_mask
;
532 m
.i_pressed
&= ~button_mask
;
535 case VOUT_DISPLAY_EVENT_MOUSE_DOUBLE_CLICK
:
536 msg_Dbg(vd
, "VoutDisplayEvent 'double click'");
538 m
.b_double_click
= true;
541 vlc_assert_unreachable();
545 vlc_mutex_unlock(&osys
->lock
);
549 /* Emulate double-click if needed */
550 if (!vd
->info
.has_double_click
&&
551 vlc_mouse_HasPressed(&osys
->mouse
.state
, &m
, MOUSE_BUTTON_LEFT
)) {
552 const mtime_t i_date
= mdate();
554 if (i_date
- osys
->mouse
.last_pressed
< osys
->mouse
.double_click_timeout
) {
555 m
.b_double_click
= true;
556 osys
->mouse
.last_pressed
= 0;
558 osys
->mouse
.last_pressed
= mdate();
563 osys
->mouse
.state
= m
;
566 osys
->mouse
.ch_activity
= true;
567 osys
->mouse
.last_moved
= mdate();
570 vout_SendDisplayEventMouse(osys
->vout
, &m
);
571 vlc_mutex_unlock(&osys
->lock
);
574 static void VoutDisplayEvent(vout_display_t
*vd
, int event
, va_list args
)
576 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
579 case VOUT_DISPLAY_EVENT_CLOSE
: {
580 msg_Dbg(vd
, "VoutDisplayEvent 'close'");
581 vout_SendEventClose(osys
->vout
);
584 case VOUT_DISPLAY_EVENT_KEY
: {
585 const int key
= (int)va_arg(args
, int);
586 msg_Dbg(vd
, "VoutDisplayEvent 'key' 0x%2.2x", key
);
587 vout_SendEventKey(osys
->vout
, key
);
590 case VOUT_DISPLAY_EVENT_MOUSE_STATE
:
591 case VOUT_DISPLAY_EVENT_MOUSE_MOVED
:
592 case VOUT_DISPLAY_EVENT_MOUSE_PRESSED
:
593 case VOUT_DISPLAY_EVENT_MOUSE_RELEASED
:
594 case VOUT_DISPLAY_EVENT_MOUSE_DOUBLE_CLICK
:
595 VoutDisplayEventMouse(vd
, event
, args
);
598 case VOUT_DISPLAY_EVENT_VIEWPOINT_MOVED
:
599 vout_SendEventViewpointMoved(osys
->vout
,
600 va_arg(args
, const vlc_viewpoint_t
*));
603 #if defined(_WIN32) || defined(__OS2__)
604 case VOUT_DISPLAY_EVENT_FULLSCREEN
: {
605 const int is_fullscreen
= (int)va_arg(args
, int);
606 const bool window_fullscreen
= va_arg(args
, int);
608 msg_Dbg(vd
, "VoutDisplayEvent 'fullscreen' %d", is_fullscreen
);
610 vlc_mutex_lock(&osys
->lock
);
611 if (!is_fullscreen
!= !osys
->is_fullscreen
) {
612 osys
->ch_fullscreen
= true;
613 osys
->is_fullscreen
= is_fullscreen
;
614 osys
->window_fullscreen
= window_fullscreen
;
616 vlc_mutex_unlock(&osys
->lock
);
620 case VOUT_DISPLAY_EVENT_WINDOW_STATE
: {
621 const unsigned state
= va_arg(args
, unsigned);
623 msg_Dbg(vd
, "VoutDisplayEvent 'window state' %u", state
);
625 vlc_mutex_lock(&osys
->lock
);
626 if (state
!= osys
->wm_state
) {
627 osys
->ch_wm_state
= true;
628 osys
->wm_state
= state
;
630 vlc_mutex_unlock(&osys
->lock
);
634 case VOUT_DISPLAY_EVENT_DISPLAY_SIZE
: {
635 const int width
= (int)va_arg(args
, int);
636 const int height
= (int)va_arg(args
, int);
637 msg_Dbg(vd
, "VoutDisplayEvent 'resize' %dx%d", width
, height
);
640 vlc_mutex_lock(&osys
->lock
);
642 osys
->ch_display_size
= true;
643 osys
->display_width
= width
;
644 osys
->display_height
= height
;
646 vlc_mutex_unlock(&osys
->lock
);
650 case VOUT_DISPLAY_EVENT_PICTURES_INVALID
: {
651 msg_Warn(vd
, "VoutDisplayEvent 'pictures invalid'");
654 assert(vd
->info
.has_pictures_invalid
);
656 vlc_mutex_lock(&osys
->lock
);
657 osys
->reset_pictures
= true;
658 vlc_mutex_unlock(&osys
->lock
);
662 msg_Err(vd
, "VoutDisplayEvent received event %d", event
);
663 /* TODO add an assert when all event are handled */
668 static vout_window_t
*VoutDisplayNewWindow(vout_display_t
*vd
, unsigned type
)
670 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
671 vout_window_t
*window
= vout_NewDisplayWindow(osys
->vout
, type
);
673 vout_display_window_Attach(window
, vd
);
677 static void VoutDisplayDelWindow(vout_display_t
*vd
, vout_window_t
*window
)
679 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
682 vout_display_window_Detach(window
);
683 vout_DeleteDisplayWindow(osys
->vout
, window
);
686 static void VoutDisplayFitWindow(vout_display_t
*vd
, bool default_size
)
688 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
689 vout_display_cfg_t cfg
= osys
->cfg
;
691 if (!cfg
.is_display_filled
)
694 cfg
.display
.width
= 0;
696 cfg
.display
.height
= 0;
702 unsigned display_width
;
703 unsigned display_height
;
704 vout_display_GetDefaultDisplaySize(&display_width
, &display_height
,
706 vout_SetDisplayWindowSize(osys
->vout
, display_width
, display_height
);
709 static void VoutDisplayCropRatio(int *left
, int *top
, int *right
, int *bottom
,
710 const video_format_t
*source
,
711 unsigned num
, unsigned den
)
713 unsigned scaled_width
= (uint64_t)source
->i_visible_height
* num
* source
->i_sar_den
/ den
/ source
->i_sar_num
;
714 unsigned scaled_height
= (uint64_t)source
->i_visible_width
* den
* source
->i_sar_num
/ num
/ source
->i_sar_den
;
716 if (scaled_width
< source
->i_visible_width
) {
717 *left
= (source
->i_visible_width
- scaled_width
) / 2;
719 *right
= *left
+ scaled_width
;
720 *bottom
= *top
+ source
->i_visible_height
;
723 *top
= (source
->i_visible_height
- scaled_height
) / 2;
724 *right
= *left
+ source
->i_visible_width
;
725 *bottom
= *top
+ scaled_height
;
729 bool vout_ManageDisplay(vout_display_t
*vd
, bool allow_reset_pictures
)
731 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
733 vout_display_Manage(vd
);
735 /* Handle mouse timeout */
736 const mtime_t date
= mdate();
737 bool hide_mouse
= false;
739 vlc_mutex_lock(&osys
->lock
);
741 if (!osys
->mouse
.is_hidden
&&
742 osys
->mouse
.last_moved
+ osys
->mouse
.hide_timeout
< date
) {
743 osys
->mouse
.is_hidden
= hide_mouse
= true;
744 } else if (osys
->mouse
.ch_activity
) {
745 if (osys
->mouse
.is_hidden
)
746 vout_HideWindowMouse(osys
->vout
, false);
747 osys
->mouse
.is_hidden
= false;
749 osys
->mouse
.ch_activity
= false;
750 vlc_mutex_unlock(&osys
->lock
);
753 msg_Dbg(vd
, "auto hiding mouse cursor");
754 if (vout_HideWindowMouse(osys
->vout
, true) != VLC_SUCCESS
755 && vd
->info
.needs_hide_mouse
)
756 vout_display_Control(vd
, VOUT_DISPLAY_HIDE_MOUSE
);
759 bool reset_render
= false;
762 vlc_mutex_lock(&osys
->lock
);
763 #if defined(_WIN32) || defined(__OS2__)
764 bool ch_fullscreen
= osys
->ch_fullscreen
;
765 bool is_fullscreen
= osys
->is_fullscreen
;
766 osys
->ch_fullscreen
= false;
768 bool ch_wm_state
= osys
->ch_wm_state
;
769 unsigned wm_state
= osys
->wm_state
;
770 osys
->ch_wm_state
= false;
773 bool ch_display_size
= osys
->ch_display_size
;
774 int display_width
= osys
->display_width
;
775 int display_height
= osys
->display_height
;
776 osys
->ch_display_size
= false;
779 if (allow_reset_pictures
) {
780 reset_pictures
= osys
->reset_pictures
;
781 osys
->reset_pictures
= false;
783 reset_pictures
= false;
786 vlc_mutex_unlock(&osys
->lock
);
788 if (!ch_display_size
&&
790 osys
->is_display_filled
== osys
->cfg
.is_display_filled
&&
792 #if defined(_WIN32) || defined(__OS2__)
798 !osys
->ch_viewpoint
) {
800 if (osys
->fit_window
!= 0) {
801 VoutDisplayFitWindow(vd
, osys
->fit_window
== -1);
802 osys
->fit_window
= 0;
809 #if defined(_WIN32) || defined(__OS2__)
811 if (osys
->window_fullscreen
812 || vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_FULLSCREEN
,
813 is_fullscreen
) == VLC_SUCCESS
) {
814 osys
->cfg
.is_fullscreen
= is_fullscreen
;
816 if (!is_fullscreen
&& !osys
->window_fullscreen
)
817 vout_SetDisplayWindowSize(osys
->vout
, osys
->width_saved
,
820 is_fullscreen
= osys
->cfg
.is_fullscreen
;
822 msg_Err(vd
, "Failed to set fullscreen");
828 if (ch_display_size
) {
829 #if defined(_WIN32) || defined(__OS2__)
830 osys
->width_saved
= osys
->cfg
.display
.width
;
831 osys
->height_saved
= osys
->cfg
.display
.height
;
833 osys
->cfg
.display
.width
= display_width
;
834 osys
->cfg
.display
.height
= display_height
;
836 vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_DISPLAY_SIZE
,
840 if (osys
->is_display_filled
!= osys
->cfg
.is_display_filled
) {
841 osys
->cfg
.is_display_filled
= osys
->is_display_filled
;
843 vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_DISPLAY_FILLED
,
848 osys
->fit_window
= -1;
849 osys
->cfg
.zoom
.num
= osys
->zoom
.num
;
850 osys
->cfg
.zoom
.den
= osys
->zoom
.den
;
851 osys
->ch_zoom
= false;
853 vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_ZOOM
, &osys
->cfg
);
855 #if defined(_WIN32) || defined(__OS2__)
858 if (vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_WINDOW_STATE
, wm_state
)) {
859 msg_Err(vd
, "Failed to set on top");
860 wm_state
= osys
->wm_state
;
862 osys
->wm_state_initial
= wm_state
;
867 if (osys
->sar
.num
> 0 && osys
->sar
.den
> 0) {
868 vd
->source
.i_sar_num
= osys
->sar
.num
;
869 vd
->source
.i_sar_den
= osys
->sar
.den
;
871 vd
->source
.i_sar_num
= osys
->source
.i_sar_num
;
872 vd
->source
.i_sar_den
= osys
->source
.i_sar_den
;
875 vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_SOURCE_ASPECT
);
876 if (!osys
->fit_window
)
877 osys
->fit_window
= 1;
878 osys
->sar
.num
= vd
->source
.i_sar_num
;
879 osys
->sar
.den
= vd
->source
.i_sar_den
;
880 osys
->ch_sar
= false;
882 /* If a crop ratio is requested, recompute the parameters */
883 if (osys
->crop
.num
!= 0 && osys
->crop
.den
!= 0)
884 osys
->ch_crop
= true;
888 unsigned crop_num
= osys
->crop
.num
;
889 unsigned crop_den
= osys
->crop
.den
;
890 if (crop_num
!= 0 && crop_den
!= 0) {
891 video_format_t fmt
= osys
->source
;
892 fmt
.i_sar_num
= vd
->source
.i_sar_num
;
893 fmt
.i_sar_den
= vd
->source
.i_sar_den
;
894 VoutDisplayCropRatio(&osys
->crop
.left
, &osys
->crop
.top
,
895 &osys
->crop
.right
, &osys
->crop
.bottom
,
896 &fmt
, crop_num
, crop_den
);
898 const int right_max
= osys
->source
.i_x_offset
+ osys
->source
.i_visible_width
;
899 const int bottom_max
= osys
->source
.i_y_offset
+ osys
->source
.i_visible_height
;
900 int left
= VLC_CLIP((int)osys
->source
.i_x_offset
+ osys
->crop
.left
,
902 int top
= VLC_CLIP((int)osys
->source
.i_y_offset
+ osys
->crop
.top
,
905 if (osys
->crop
.right
<= 0)
906 right
= (int)(osys
->source
.i_x_offset
+ osys
->source
.i_visible_width
) + osys
->crop
.right
;
908 right
= (int)osys
->source
.i_x_offset
+ osys
->crop
.right
;
909 right
= VLC_CLIP(right
, left
+ 1, right_max
);
910 if (osys
->crop
.bottom
<= 0)
911 bottom
= (int)(osys
->source
.i_y_offset
+ osys
->source
.i_visible_height
) + osys
->crop
.bottom
;
913 bottom
= (int)osys
->source
.i_y_offset
+ osys
->crop
.bottom
;
914 bottom
= VLC_CLIP(bottom
, top
+ 1, bottom_max
);
916 vd
->source
.i_x_offset
= left
;
917 vd
->source
.i_y_offset
= top
;
918 vd
->source
.i_visible_width
= right
- left
;
919 vd
->source
.i_visible_height
= bottom
- top
;
920 video_format_Print(VLC_OBJECT(vd
), "SOURCE ", &osys
->source
);
921 video_format_Print(VLC_OBJECT(vd
), "CROPPED", &vd
->source
);
922 vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_SOURCE_CROP
);
924 if (!osys
->fit_window
)
925 osys
->fit_window
= 1;
926 osys
->crop
.left
= left
- osys
->source
.i_x_offset
;
927 osys
->crop
.top
= top
- osys
->source
.i_y_offset
;
928 /* FIXME for right/bottom we should keep the 'type' border vs window */
929 osys
->crop
.right
= right
-
930 (osys
->source
.i_x_offset
+ osys
->source
.i_visible_width
);
931 osys
->crop
.bottom
= bottom
-
932 (osys
->source
.i_y_offset
+ osys
->source
.i_visible_height
);
933 osys
->crop
.num
= crop_num
;
934 osys
->crop
.den
= crop_den
;
935 osys
->ch_crop
= false;
937 if (osys
->ch_viewpoint
) {
938 vout_display_cfg_t cfg
= osys
->cfg
;
940 cfg
.viewpoint
= osys
->viewpoint
;
942 if (vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_VIEWPOINT
, &cfg
)) {
943 msg_Err(vd
, "Failed to change Viewpoint");
944 osys
->viewpoint
= osys
->cfg
.viewpoint
;
946 osys
->cfg
.viewpoint
= osys
->viewpoint
;
947 osys
->ch_viewpoint
= false;
951 if (reset_pictures
) {
952 if (vout_display_Control(vd
, VOUT_DISPLAY_RESET_PICTURES
)) {
953 /* FIXME what to do here ? */
954 msg_Err(vd
, "Failed to reset pictures (probably fatal)");
960 VoutDisplayResetRender(vd
);
965 bool vout_AreDisplayPicturesInvalid(vout_display_t
*vd
)
967 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
969 vlc_mutex_lock(&osys
->lock
);
970 const bool reset_pictures
= osys
->reset_pictures
;
971 vlc_mutex_unlock(&osys
->lock
);
973 return reset_pictures
;
976 bool vout_IsDisplayFiltered(vout_display_t
*vd
)
978 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
980 return osys
->filters
== NULL
|| !filter_chain_IsEmpty(osys
->filters
);
983 picture_t
*vout_FilterDisplay(vout_display_t
*vd
, picture_t
*picture
)
985 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
987 if (osys
->filters
== NULL
) {
988 picture_Release(picture
);
992 return filter_chain_VideoFilter(osys
->filters
, picture
);
995 void vout_FilterFlush(vout_display_t
*vd
)
997 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
999 if (osys
->filters
!= NULL
)
1000 filter_chain_VideoFlush(osys
->filters
);
1003 void vout_UpdateDisplaySourceProperties(vout_display_t
*vd
, const video_format_t
*source
)
1005 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1007 if (source
->i_sar_num
* osys
->source
.i_sar_den
!=
1008 source
->i_sar_den
* osys
->source
.i_sar_num
) {
1010 osys
->source
.i_sar_num
= source
->i_sar_num
;
1011 osys
->source
.i_sar_den
= source
->i_sar_den
;
1012 vlc_ureduce(&osys
->source
.i_sar_num
, &osys
->source
.i_sar_den
,
1013 osys
->source
.i_sar_num
, osys
->source
.i_sar_den
, 0);
1015 /* FIXME it will override any AR that the user would have forced */
1016 osys
->ch_sar
= true;
1017 osys
->sar
.num
= osys
->source
.i_sar_num
;
1018 osys
->sar
.den
= osys
->source
.i_sar_den
;
1020 if (source
->i_x_offset
!= osys
->source
.i_x_offset
||
1021 source
->i_y_offset
!= osys
->source
.i_y_offset
||
1022 source
->i_visible_width
!= osys
->source
.i_visible_width
||
1023 source
->i_visible_height
!= osys
->source
.i_visible_height
) {
1025 video_format_CopyCrop(&osys
->source
, source
);
1027 /* Force the vout to reapply the current user crop settings over the new decoder
1029 osys
->ch_crop
= true;
1033 void vout_SetDisplayFilled(vout_display_t
*vd
, bool is_filled
)
1035 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1037 osys
->is_display_filled
= is_filled
;
1040 void vout_SetDisplayZoom(vout_display_t
*vd
, unsigned num
, unsigned den
)
1042 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1044 if (num
!= 0 && den
!= 0) {
1045 vlc_ureduce(&num
, &den
, num
, den
, 0);
1051 if (10 * num
<= den
) {
1054 } else if (num
>= 10 * den
) {
1059 if (osys
->is_display_filled
||
1060 osys
->zoom
.num
!= num
|| osys
->zoom
.den
!= den
) {
1061 osys
->ch_zoom
= true;
1062 osys
->zoom
.num
= num
;
1063 osys
->zoom
.den
= den
;
1067 void vout_SetDisplayAspect(vout_display_t
*vd
, unsigned dar_num
, unsigned dar_den
)
1069 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1071 unsigned sar_num
, sar_den
;
1072 if (dar_num
> 0 && dar_den
> 0) {
1073 sar_num
= dar_num
* osys
->source
.i_visible_height
;
1074 sar_den
= dar_den
* osys
->source
.i_visible_width
;
1075 vlc_ureduce(&sar_num
, &sar_den
, sar_num
, sar_den
, 0);
1081 if (osys
->sar
.num
!= sar_num
|| osys
->sar
.den
!= sar_den
) {
1082 osys
->ch_sar
= true;
1083 osys
->sar
.num
= sar_num
;
1084 osys
->sar
.den
= sar_den
;
1087 void vout_SetDisplayCrop(vout_display_t
*vd
,
1088 unsigned crop_num
, unsigned crop_den
,
1089 unsigned left
, unsigned top
, int right
, int bottom
)
1091 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1093 if (osys
->crop
.left
!= (int)left
|| osys
->crop
.top
!= (int)top
||
1094 osys
->crop
.right
!= right
|| osys
->crop
.bottom
!= bottom
||
1095 (crop_num
!= 0 && crop_den
!= 0 &&
1096 (crop_num
!= osys
->crop
.num
|| crop_den
!= osys
->crop
.den
))) {
1098 osys
->crop
.left
= left
;
1099 osys
->crop
.top
= top
;
1100 osys
->crop
.right
= right
;
1101 osys
->crop
.bottom
= bottom
;
1102 osys
->crop
.num
= crop_num
;
1103 osys
->crop
.den
= crop_den
;
1105 osys
->ch_crop
= true;
1109 void vout_SetDisplayViewpoint(vout_display_t
*vd
,
1110 const vlc_viewpoint_t
*p_viewpoint
)
1112 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1114 if (osys
->viewpoint
.yaw
!= p_viewpoint
->yaw
||
1115 osys
->viewpoint
.pitch
!= p_viewpoint
->pitch
||
1116 osys
->viewpoint
.roll
!= p_viewpoint
->roll
||
1117 osys
->viewpoint
.fov
!= p_viewpoint
->fov
) {
1118 osys
->viewpoint
= *p_viewpoint
;
1120 osys
->ch_viewpoint
= true;
1124 static vout_display_t
*DisplayNew(vout_thread_t
*vout
,
1125 const video_format_t
*source
,
1126 const vout_display_state_t
*state
,
1127 const char *module
, bool is_splitter
,
1128 mtime_t double_click_timeout
,
1129 mtime_t hide_timeout
,
1130 const vout_display_owner_t
*owner_ptr
)
1133 vout_display_owner_sys_t
*osys
= calloc(1, sizeof(*osys
));
1134 vout_display_cfg_t
*cfg
= &osys
->cfg
;
1137 osys
->sar_initial
= state
->sar
;
1138 vout_display_GetDefaultDisplaySize(&cfg
->display
.width
, &cfg
->display
.height
,
1142 osys
->is_splitter
= is_splitter
;
1144 vlc_mutex_init(&osys
->lock
);
1146 vlc_mouse_Init(&osys
->mouse
.state
);
1147 osys
->mouse
.last_moved
= mdate();
1148 osys
->mouse
.double_click_timeout
= double_click_timeout
;
1149 osys
->mouse
.hide_timeout
= hide_timeout
;
1150 osys
->display_width
= cfg
->display
.width
;
1151 osys
->display_height
= cfg
->display
.height
;
1152 osys
->is_display_filled
= cfg
->is_display_filled
;
1153 osys
->viewpoint
= cfg
->viewpoint
;
1155 osys
->zoom
.num
= cfg
->zoom
.num
;
1156 osys
->zoom
.den
= cfg
->zoom
.den
;
1157 #if defined(_WIN32) || defined(__OS2__)
1158 osys
->is_fullscreen
= cfg
->is_fullscreen
;
1159 osys
->width_saved
= cfg
->display
.width
;
1160 osys
->height_saved
= cfg
->display
.height
;
1161 if (osys
->is_fullscreen
) {
1162 vout_display_cfg_t cfg_windowed
= *cfg
;
1163 cfg_windowed
.is_fullscreen
= false;
1164 cfg_windowed
.display
.width
= 0;
1165 cfg_windowed
.display
.height
= 0;
1166 vout_display_GetDefaultDisplaySize(&osys
->width_saved
,
1167 &osys
->height_saved
,
1168 source
, &cfg_windowed
);
1171 osys
->wm_state_initial
= VOUT_WINDOW_STATE_NORMAL
;
1172 osys
->wm_state
= state
->wm_state
;
1173 osys
->ch_wm_state
= true;
1175 osys
->fit_window
= 0;
1177 osys
->source
= *source
;
1178 osys
->crop
.left
= 0;
1180 osys
->crop
.right
= 0;
1181 osys
->crop
.bottom
= 0;
1185 osys
->sar
.num
= osys
->sar_initial
.num
? osys
->sar_initial
.num
: source
->i_sar_num
;
1186 osys
->sar
.den
= osys
->sar_initial
.den
? osys
->sar_initial
.den
: source
->i_sar_den
;
1188 vout_display_owner_t owner
;
1192 owner
.event
= VoutDisplayEvent
;
1193 owner
.window_new
= VoutDisplayNewWindow
;
1194 owner
.window_del
= VoutDisplayDelWindow
;
1198 vout_display_t
*p_display
= vout_display_New(VLC_OBJECT(vout
),
1199 module
, !is_splitter
,
1200 source
, cfg
, &owner
);
1204 if (VoutDisplayCreateRender(p_display
)) {
1205 vout_display_Delete(p_display
);
1209 /* Setup delayed request */
1210 if (osys
->sar
.num
!= source
->i_sar_num
||
1211 osys
->sar
.den
!= source
->i_sar_den
)
1212 osys
->ch_sar
= true;
1214 vout_SendEventViewpointChangeable(osys
->vout
,
1215 p_display
->fmt
.projection_mode
!= PROJECTION_MODE_RECTANGULAR
);
1219 vlc_mutex_destroy(&osys
->lock
);
1224 void vout_DeleteDisplay(vout_display_t
*vd
, vout_display_state_t
*state
)
1226 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1229 if (!osys
->is_splitter
)
1230 state
->cfg
= osys
->cfg
;
1231 #if defined(_WIN32) || defined(__OS2__)
1232 state
->wm_state
= osys
->wm_state
;
1234 state
->sar
= osys
->sar_initial
;
1237 VoutDisplayDestroyRender(vd
);
1238 if (osys
->is_splitter
)
1240 vout_display_Delete(vd
);
1241 vlc_mutex_destroy(&osys
->lock
);
1245 /*****************************************************************************
1247 *****************************************************************************/
1248 vout_display_t
*vout_NewDisplay(vout_thread_t
*vout
,
1249 const video_format_t
*source
,
1250 const vout_display_state_t
*state
,
1252 mtime_t double_click_timeout
,
1253 mtime_t hide_timeout
)
1255 return DisplayNew(vout
, source
, state
, module
, false,
1256 double_click_timeout
, hide_timeout
, NULL
);
1259 /*****************************************************************************
1261 *****************************************************************************/
1262 struct vout_display_sys_t
{
1263 picture_pool_t
*pool
;
1264 video_splitter_t
*splitter
;
1268 picture_t
**picture
;
1269 vout_display_t
**display
;
1271 struct video_splitter_owner_t
{
1272 vout_display_t
*wrapper
;
1275 static vout_window_t
*SplitterNewWindow(vout_display_t
*vd
, unsigned type
)
1277 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1278 vout_window_t
*window
;
1279 vout_window_cfg_t cfg
= {
1281 .width
= vd
->cfg
->display
.width
,
1282 .height
= vd
->cfg
->display
.height
,
1283 .is_standalone
= true,
1286 window
= vout_display_window_New(osys
->vout
, &cfg
);
1288 vout_display_window_Attach(window
, vd
);
1292 static void SplitterDelWindow(vout_display_t
*vd
, vout_window_t
*window
)
1294 if (window
!= NULL
) {
1295 vout_display_window_Detach(window
);
1296 vout_display_window_Delete(window
);
1301 static void SplitterEvent(vout_display_t
*vd
, int event
, va_list args
)
1303 //vout_display_owner_sys_t *osys = vd->owner.sys;
1307 case VOUT_DISPLAY_EVENT_MOUSE_STATE
:
1308 case VOUT_DISPLAY_EVENT_MOUSE_MOVED
:
1309 case VOUT_DISPLAY_EVENT_MOUSE_PRESSED
:
1310 case VOUT_DISPLAY_EVENT_MOUSE_RELEASED
:
1314 case VOUT_DISPLAY_EVENT_MOUSE_DOUBLE_CLICK
:
1315 case VOUT_DISPLAY_EVENT_KEY
:
1316 case VOUT_DISPLAY_EVENT_CLOSE
:
1317 case VOUT_DISPLAY_EVENT_DISPLAY_SIZE
:
1318 case VOUT_DISPLAY_EVENT_PICTURES_INVALID
:
1319 VoutDisplayEvent(vd
, event
, args
);
1323 msg_Err(vd
, "splitter event not implemented: %d", event
);
1328 static picture_pool_t
*SplitterPool(vout_display_t
*vd
, unsigned count
)
1330 vout_display_sys_t
*sys
= vd
->sys
;
1332 sys
->pool
= picture_pool_NewFromFormat(&vd
->fmt
, count
);
1335 static void SplitterPrepare(vout_display_t
*vd
,
1337 subpicture_t
*subpicture
)
1339 vout_display_sys_t
*sys
= vd
->sys
;
1341 picture_Hold(picture
);
1342 assert(!subpicture
);
1344 if (video_splitter_Filter(sys
->splitter
, sys
->picture
, picture
)) {
1345 for (int i
= 0; i
< sys
->count
; i
++)
1346 sys
->picture
[i
] = NULL
;
1350 for (int i
= 0; i
< sys
->count
; i
++) {
1351 sys
->picture
[i
] = vout_FilterDisplay(sys
->display
[i
], sys
->picture
[i
]);
1352 if (sys
->picture
[i
])
1353 vout_display_Prepare(sys
->display
[i
], sys
->picture
[i
], NULL
);
1356 static void SplitterDisplay(vout_display_t
*vd
,
1358 subpicture_t
*subpicture
)
1360 vout_display_sys_t
*sys
= vd
->sys
;
1362 assert(!subpicture
);
1363 for (int i
= 0; i
< sys
->count
; i
++) {
1364 if (sys
->picture
[i
])
1365 vout_display_Display(sys
->display
[i
], sys
->picture
[i
], NULL
);
1367 picture_Release(picture
);
1369 static int SplitterControl(vout_display_t
*vd
, int query
, va_list args
)
1371 (void)vd
; (void)query
; (void)args
;
1372 return VLC_EGENERIC
;
1374 static void SplitterManage(vout_display_t
*vd
)
1376 vout_display_sys_t
*sys
= vd
->sys
;
1378 for (int i
= 0; i
< sys
->count
; i
++)
1379 vout_ManageDisplay(sys
->display
[i
], true);
1382 static int SplitterPictureNew(video_splitter_t
*splitter
, picture_t
*picture
[])
1384 vout_display_sys_t
*wsys
= splitter
->p_owner
->wrapper
->sys
;
1386 for (int i
= 0; i
< wsys
->count
; i
++) {
1387 if (vout_IsDisplayFiltered(wsys
->display
[i
])) {
1388 /* TODO use a pool ? */
1389 picture
[i
] = picture_NewFromFormat(&wsys
->display
[i
]->source
);
1391 picture_pool_t
*pool
= vout_display_Pool(wsys
->display
[i
], 3);
1392 picture
[i
] = pool
? picture_pool_Get(pool
) : NULL
;
1395 for (int j
= 0; j
< i
; j
++)
1396 picture_Release(picture
[j
]);
1397 return VLC_EGENERIC
;
1402 static void SplitterPictureDel(video_splitter_t
*splitter
, picture_t
*picture
[])
1404 vout_display_sys_t
*wsys
= splitter
->p_owner
->wrapper
->sys
;
1406 for (int i
= 0; i
< wsys
->count
; i
++)
1407 picture_Release(picture
[i
]);
1409 static void SplitterClose(vout_display_t
*vd
)
1411 vout_display_sys_t
*sys
= vd
->sys
;
1414 video_splitter_t
*splitter
= sys
->splitter
;
1415 free(splitter
->p_owner
);
1416 video_splitter_Delete(splitter
);
1419 picture_pool_Release(sys
->pool
);
1422 for (int i
= 0; i
< sys
->count
; i
++)
1423 vout_DeleteDisplay(sys
->display
[i
], NULL
);
1424 TAB_CLEAN(sys
->count
, sys
->display
);
1430 vout_display_t
*vout_NewSplitter(vout_thread_t
*vout
,
1431 const video_format_t
*source
,
1432 const vout_display_state_t
*state
,
1434 const char *splitter_module
,
1435 mtime_t double_click_timeout
,
1436 mtime_t hide_timeout
)
1438 video_splitter_t
*splitter
=
1439 video_splitter_New(VLC_OBJECT(vout
), splitter_module
, source
);
1444 vout_display_t
*wrapper
=
1445 DisplayNew(vout
, source
, state
, module
, true,
1446 double_click_timeout
, hide_timeout
, NULL
);
1448 video_splitter_Delete(splitter
);
1451 vout_display_sys_t
*sys
= malloc(sizeof(*sys
));
1454 sys
->picture
= calloc(splitter
->i_output
, sizeof(*sys
->picture
));
1457 sys
->splitter
= splitter
;
1460 wrapper
->pool
= SplitterPool
;
1461 wrapper
->prepare
= SplitterPrepare
;
1462 wrapper
->display
= SplitterDisplay
;
1463 wrapper
->control
= SplitterControl
;
1464 wrapper
->manage
= SplitterManage
;
1468 video_splitter_owner_t
*vso
= xmalloc(sizeof(*vso
));
1469 vso
->wrapper
= wrapper
;
1470 splitter
->p_owner
= vso
;
1471 splitter
->pf_picture_new
= SplitterPictureNew
;
1472 splitter
->pf_picture_del
= SplitterPictureDel
;
1475 TAB_INIT(sys
->count
, sys
->display
);
1476 for (int i
= 0; i
< splitter
->i_output
; i
++) {
1477 vout_display_owner_t vdo
= {
1478 .event
= SplitterEvent
,
1479 .window_new
= SplitterNewWindow
,
1480 .window_del
= SplitterDelWindow
,
1482 const video_splitter_output_t
*output
= &splitter
->p_output
[i
];
1483 vout_display_state_t ostate
;
1485 memset(&ostate
, 0, sizeof(ostate
));
1486 ostate
.cfg
.display
= state
->cfg
.display
;
1487 ostate
.cfg
.align
.horizontal
= 0; /* TODO */
1488 ostate
.cfg
.align
.vertical
= 0; /* TODO */
1489 ostate
.cfg
.is_display_filled
= true;
1490 ostate
.cfg
.zoom
.num
= 1;
1491 ostate
.cfg
.zoom
.den
= 1;
1493 vout_display_t
*vd
= DisplayNew(vout
, &output
->fmt
, &ostate
,
1494 output
->psz_module
? output
->psz_module
: module
,
1496 double_click_timeout
, hide_timeout
, &vdo
);
1498 vout_DeleteDisplay(wrapper
, NULL
);
1501 TAB_APPEND(sys
->count
, sys
->display
, vd
);
1507 /*****************************************************************************
1509 *****************************************************************************/
1510 #include "vout_internal.h"
1511 void vout_SendDisplayEventMouse(vout_thread_t
*vout
, const vlc_mouse_t
*m
)
1513 vlc_mouse_t tmp1
, tmp2
;
1515 /* The check on spu is needed as long as ALLOW_DUMMY_VOUT is defined */
1516 if (vout
->p
->spu
&& spu_ProcessMouse( vout
->p
->spu
, m
, &vout
->p
->display
.vd
->source
))
1519 vlc_mutex_lock( &vout
->p
->filter
.lock
);
1520 if (vout
->p
->filter
.chain_static
&& vout
->p
->filter
.chain_interactive
) {
1521 if (!filter_chain_MouseFilter(vout
->p
->filter
.chain_interactive
, &tmp1
, m
))
1523 if (!filter_chain_MouseFilter(vout
->p
->filter
.chain_static
, &tmp2
, m
))
1526 vlc_mutex_unlock( &vout
->p
->filter
.lock
);
1528 if (vlc_mouse_HasMoved(&vout
->p
->mouse
, m
)) {
1529 vout_SendEventMouseMoved(vout
, m
->i_x
, m
->i_y
);
1531 if (vlc_mouse_HasButton(&vout
->p
->mouse
, m
)) {
1532 for (unsigned button
= 0; button
< MOUSE_BUTTON_MAX
; button
++) {
1533 if (vlc_mouse_HasPressed(&vout
->p
->mouse
, m
, button
))
1534 vout_SendEventMousePressed(vout
, button
);
1535 else if (vlc_mouse_HasReleased(&vout
->p
->mouse
, m
, button
))
1536 vout_SendEventMouseReleased(vout
, button
);
1539 if (m
->b_double_click
)
1540 vout_SendEventMouseDoubleClick(vout
);
1541 vout
->p
->mouse
= *m
;