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 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
.has_hide_mouse
= false;
95 vd
->info
.has_pictures_invalid
= false;
96 vd
->info
.has_event_thread
= false;
97 vd
->info
.subpicture_chromas
= NULL
;
110 vd
->module
= module_need(vd
, "vout display", module
, module
&& *module
!= '\0');
112 vlc_object_release(vd
);
122 * It deletes a vout_display_t
124 static void vout_display_Delete(vout_display_t
*vd
)
127 module_unneed(vd
, vd
->module
);
129 video_format_Clean(&vd
->source
);
130 video_format_Clean(&vd
->fmt
);
132 vlc_object_release(vd
);
136 * It controls a vout_display_t
138 static int vout_display_Control(vout_display_t
*vd
, int query
, ...)
143 va_start(args
, query
);
144 result
= vd
->control(vd
, query
, args
);
150 static void vout_display_Manage(vout_display_t
*vd
)
157 void vout_display_GetDefaultDisplaySize(unsigned *width
, unsigned *height
,
158 const video_format_t
*source
,
159 const vout_display_cfg_t
*cfg
)
161 if (cfg
->display
.width
> 0 && cfg
->display
.height
> 0) {
162 *width
= cfg
->display
.width
;
163 *height
= cfg
->display
.height
;
164 } else if (cfg
->display
.width
> 0) {
165 *width
= cfg
->display
.width
;
166 *height
= (int64_t)source
->i_visible_height
* source
->i_sar_den
* cfg
->display
.width
* cfg
->display
.sar
.num
/
167 source
->i_visible_width
/ source
->i_sar_num
/ cfg
->display
.sar
.den
;
168 } else if (cfg
->display
.height
> 0) {
169 *width
= (int64_t)source
->i_visible_width
* source
->i_sar_num
* cfg
->display
.height
* cfg
->display
.sar
.den
/
170 source
->i_visible_height
/ source
->i_sar_den
/ cfg
->display
.sar
.num
;
171 *height
= cfg
->display
.height
;
172 } else if (source
->i_sar_num
>= source
->i_sar_den
) {
173 *width
= (int64_t)source
->i_visible_width
* source
->i_sar_num
* cfg
->display
.sar
.den
/ source
->i_sar_den
/ cfg
->display
.sar
.num
;
174 *height
= source
->i_visible_height
;
176 *width
= source
->i_visible_width
;
177 *height
= (int64_t)source
->i_visible_height
* source
->i_sar_den
* cfg
->display
.sar
.num
/ source
->i_sar_num
/ cfg
->display
.sar
.den
;
180 *width
= *width
* cfg
->zoom
.num
/ cfg
->zoom
.den
;
181 *height
= *height
* cfg
->zoom
.num
/ cfg
->zoom
.den
;
183 if (ORIENT_IS_SWAP(source
->orientation
)) {
185 unsigned store
= *width
;
192 void vout_display_PlacePicture(vout_display_place_t
*place
,
193 const video_format_t
*source
,
194 const vout_display_cfg_t
*cfg
,
198 memset(place
, 0, sizeof(*place
));
199 if (cfg
->display
.width
<= 0 || cfg
->display
.height
<= 0)
203 unsigned display_width
;
204 unsigned display_height
;
206 video_format_t source_rot
;
207 video_format_ApplyRotation(&source_rot
, source
);
208 source
= &source_rot
;
210 if (cfg
->is_display_filled
) {
211 display_width
= cfg
->display
.width
;
212 display_height
= cfg
->display
.height
;
214 vout_display_cfg_t cfg_tmp
= *cfg
;
216 cfg_tmp
.display
.width
= 0;
217 cfg_tmp
.display
.height
= 0;
218 vout_display_GetDefaultDisplaySize(&display_width
, &display_height
,
222 display_width
= __MIN(display_width
, cfg
->display
.width
);
223 display_height
= __MIN(display_height
, cfg
->display
.height
);
227 const unsigned width
= source
->i_visible_width
;
228 const unsigned height
= source
->i_visible_height
;
229 /* Compute the height if we use the width to fill up display_width */
230 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
;
231 /* And the same but switching width/height */
232 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
;
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 /* Compute position */
244 switch (cfg
->align
.horizontal
) {
245 case VOUT_DISPLAY_ALIGN_LEFT
:
248 case VOUT_DISPLAY_ALIGN_RIGHT
:
249 place
->x
= cfg
->display
.width
- place
->width
;
252 place
->x
= ((int)cfg
->display
.width
- (int)place
->width
) / 2;
256 switch (cfg
->align
.vertical
) {
257 case VOUT_DISPLAY_ALIGN_TOP
:
260 case VOUT_DISPLAY_ALIGN_BOTTOM
:
261 place
->y
= cfg
->display
.height
- place
->height
;
264 place
->y
= ((int)cfg
->display
.height
- (int)place
->height
) / 2;
269 void vout_display_SendMouseMovedDisplayCoordinates(vout_display_t
*vd
, video_orientation_t orient_display
, int m_x
, int m_y
, vout_display_place_t
*place
)
271 video_format_t source_rot
= vd
->source
;
272 video_format_TransformTo(&source_rot
, orient_display
);
274 if (place
->width
> 0 && place
->height
> 0) {
276 int x
= (int)(source_rot
.i_x_offset
+
277 (int64_t)(m_x
- place
->x
) * source_rot
.i_visible_width
/ place
->width
);
278 int y
= (int)(source_rot
.i_y_offset
+
279 (int64_t)(m_y
- place
->y
) * source_rot
.i_visible_height
/ place
->height
);
281 video_transform_t transform
= video_format_GetTransform(vd
->source
.orientation
, orient_display
);
290 y
= vd
->source
.i_visible_height
- store
;
293 x
= vd
->source
.i_visible_width
- x
;
294 y
= vd
->source
.i_visible_height
- y
;
298 x
= vd
->source
.i_visible_width
- y
;
301 case TRANSFORM_HFLIP
:
302 x
= vd
->source
.i_visible_width
- x
;
304 case TRANSFORM_VFLIP
:
305 y
= vd
->source
.i_visible_height
- y
;
307 case TRANSFORM_TRANSPOSE
:
312 case TRANSFORM_ANTI_TRANSPOSE
:
314 x
= vd
->source
.i_visible_width
- y
;
315 y
= vd
->source
.i_visible_height
- store
;
321 vout_display_SendEventMouseMoved (vd
, x
, y
);
325 struct vout_display_owner_sys_t
{
327 bool is_wrapper
; /* Is the current display a wrapper */
328 vout_display_t
*wrapper
; /* Vout display wrapper */
331 vout_display_cfg_t cfg
;
338 unsigned width_saved
;
339 unsigned height_saved
;
347 bool ch_display_filled
;
348 bool is_display_filled
;
355 #if defined(_WIN32) || defined(__OS2__)
358 unsigned wm_state_initial
;
377 video_format_t source
;
378 filter_chain_t
*filters
;
380 /* Lock protecting the variables used by
381 * VoutDisplayEvent(ie vout_display_SendEvent) */
388 mtime_t last_pressed
;
394 mtime_t double_click_timeout
;
395 mtime_t hide_timeout
;
403 bool ch_display_size
;
415 static int VoutDisplayCreateRender(vout_display_t
*vd
)
417 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
419 osys
->filters
= NULL
;
421 video_format_t v_src
= vd
->source
;
425 video_format_t v_dst
= vd
->fmt
;
429 video_format_t v_dst_cmp
= v_dst
;
430 if ((v_src
.i_chroma
== VLC_CODEC_J420
&& v_dst
.i_chroma
== VLC_CODEC_I420
) ||
431 (v_src
.i_chroma
== VLC_CODEC_J422
&& v_dst
.i_chroma
== VLC_CODEC_I422
) ||
432 (v_src
.i_chroma
== VLC_CODEC_J440
&& v_dst
.i_chroma
== VLC_CODEC_I440
) ||
433 (v_src
.i_chroma
== VLC_CODEC_J444
&& v_dst
.i_chroma
== VLC_CODEC_I444
))
434 v_dst_cmp
.i_chroma
= v_src
.i_chroma
;
436 const bool convert
= memcmp(&v_src
, &v_dst_cmp
, sizeof(v_src
)) != 0;
440 msg_Dbg(vd
, "A filter to adapt decoder to display is needed");
442 filter_owner_t owner
= {
445 .buffer_new
= VideoBufferNew
,
449 osys
->filters
= filter_chain_NewVideo(vd
, false, &owner
);
450 if (unlikely(osys
->filters
== NULL
))
451 abort(); /* TODO critical */
455 es_format_InitFromVideo(&src
, &v_src
);
459 for (int i
= 0; i
< 1 + (v_dst_cmp
.i_chroma
!= v_dst
.i_chroma
); i
++) {
462 es_format_InitFromVideo(&dst
, i
== 0 ? &v_dst
: &v_dst_cmp
);
464 filter_chain_Reset(osys
->filters
, &src
, &dst
);
465 filter
= filter_chain_AppendFilter(osys
->filters
,
466 NULL
, NULL
, &src
, &dst
);
467 es_format_Clean(&dst
);
471 es_format_Clean(&src
);
473 if (filter
== NULL
) {
474 msg_Err(vd
, "Failed to adapt decoder format to display");
475 filter_chain_Delete(osys
->filters
);
476 osys
->filters
= NULL
;
482 static void VoutDisplayDestroyRender(vout_display_t
*vd
)
484 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
487 filter_chain_Delete(osys
->filters
);
490 static int VoutDisplayResetRender(vout_display_t
*vd
)
492 VoutDisplayDestroyRender(vd
);
493 return VoutDisplayCreateRender(vd
);
496 static void VoutDisplayEventMouse(vout_display_t
*vd
, int event
, va_list args
)
498 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
500 vlc_mutex_lock(&osys
->lock
);
503 vlc_mouse_t m
= osys
->mouse
.state
;
504 bool is_ignored
= false;
507 case VOUT_DISPLAY_EVENT_MOUSE_STATE
: {
508 const int x
= (int)va_arg(args
, int);
509 const int y
= (int)va_arg(args
, int);
510 const int button_mask
= (int)va_arg(args
, int);
515 m
.i_pressed
= button_mask
;
518 case VOUT_DISPLAY_EVENT_MOUSE_MOVED
: {
519 const int x
= (int)va_arg(args
, int);
520 const int y
= (int)va_arg(args
, int);
522 //msg_Dbg(vd, "VoutDisplayEvent 'mouse' @%d,%d", x, y);
526 m
.b_double_click
= false;
529 case VOUT_DISPLAY_EVENT_MOUSE_PRESSED
:
530 case VOUT_DISPLAY_EVENT_MOUSE_RELEASED
: {
531 const int button
= (int)va_arg(args
, int);
532 const int button_mask
= 1 << button
;
534 /* Ignore inconsistent event */
535 if ((event
== VOUT_DISPLAY_EVENT_MOUSE_PRESSED
&& (osys
->mouse
.state
.i_pressed
& button_mask
)) ||
536 (event
== VOUT_DISPLAY_EVENT_MOUSE_RELEASED
&& !(osys
->mouse
.state
.i_pressed
& button_mask
))) {
542 msg_Dbg(vd
, "VoutDisplayEvent 'mouse button' %d t=%d", button
, event
);
544 m
.b_double_click
= false;
545 if (event
== VOUT_DISPLAY_EVENT_MOUSE_PRESSED
)
546 m
.i_pressed
|= button_mask
;
548 m
.i_pressed
&= ~button_mask
;
551 case VOUT_DISPLAY_EVENT_MOUSE_DOUBLE_CLICK
:
552 msg_Dbg(vd
, "VoutDisplayEvent 'double click'");
554 m
.b_double_click
= true;
557 vlc_assert_unreachable();
561 vlc_mutex_unlock(&osys
->lock
);
565 /* Emulate double-click if needed */
566 if (!vd
->info
.has_double_click
&&
567 vlc_mouse_HasPressed(&osys
->mouse
.state
, &m
, MOUSE_BUTTON_LEFT
)) {
568 const mtime_t i_date
= mdate();
570 if (i_date
- osys
->mouse
.last_pressed
< osys
->mouse
.double_click_timeout
) {
571 m
.b_double_click
= true;
572 osys
->mouse
.last_pressed
= 0;
574 osys
->mouse
.last_pressed
= mdate();
579 osys
->mouse
.state
= m
;
582 osys
->mouse
.ch_activity
= true;
583 if (!vd
->info
.has_hide_mouse
)
584 osys
->mouse
.last_moved
= mdate();
587 vout_SendEventMouseVisible(osys
->vout
);
588 vout_SendDisplayEventMouse(osys
->vout
, &m
);
589 vlc_mutex_unlock(&osys
->lock
);
593 static void *VoutDisplayEventKeyDispatch(void *data
)
595 vout_display_owner_sys_t
*osys
= data
;
598 block_t
*event
= block_FifoGet(osys
->event
.fifo
);
600 int cancel
= vlc_savecancel();
603 memcpy(&key
, event
->p_buffer
, sizeof(key
));
604 vout_SendEventKey(osys
->vout
, key
);
605 block_Release(event
);
607 vlc_restorecancel(cancel
);
611 static void VoutDisplayEventKey(vout_display_t
*vd
, int key
)
613 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
615 if (!osys
->event
.fifo
) {
616 osys
->event
.fifo
= block_FifoNew();
617 if (!osys
->event
.fifo
)
619 if (vlc_clone(&osys
->event
.thread
, VoutDisplayEventKeyDispatch
,
620 osys
, VLC_THREAD_PRIORITY_LOW
)) {
621 block_FifoRelease(osys
->event
.fifo
);
622 osys
->event
.fifo
= NULL
;
626 block_t
*event
= block_Alloc(sizeof(key
));
628 memcpy(event
->p_buffer
, &key
, sizeof(key
));
629 block_FifoPut(osys
->event
.fifo
, event
);
633 static void VoutDisplayEvent(vout_display_t
*vd
, int event
, va_list args
)
635 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
638 case VOUT_DISPLAY_EVENT_CLOSE
: {
639 msg_Dbg(vd
, "VoutDisplayEvent 'close'");
640 vout_SendEventClose(osys
->vout
);
643 case VOUT_DISPLAY_EVENT_KEY
: {
644 const int key
= (int)va_arg(args
, int);
645 msg_Dbg(vd
, "VoutDisplayEvent 'key' 0x%2.2x", key
);
646 if (vd
->info
.has_event_thread
)
647 vout_SendEventKey(osys
->vout
, key
);
649 VoutDisplayEventKey(vd
, key
);
652 case VOUT_DISPLAY_EVENT_MOUSE_STATE
:
653 case VOUT_DISPLAY_EVENT_MOUSE_MOVED
:
654 case VOUT_DISPLAY_EVENT_MOUSE_PRESSED
:
655 case VOUT_DISPLAY_EVENT_MOUSE_RELEASED
:
656 case VOUT_DISPLAY_EVENT_MOUSE_DOUBLE_CLICK
:
657 VoutDisplayEventMouse(vd
, event
, args
);
660 case VOUT_DISPLAY_EVENT_FULLSCREEN
: {
661 const int is_fullscreen
= (int)va_arg(args
, int);
663 msg_Dbg(vd
, "VoutDisplayEvent 'fullscreen' %d", is_fullscreen
);
665 vlc_mutex_lock(&osys
->lock
);
666 if (!is_fullscreen
!= !osys
->is_fullscreen
) {
667 osys
->ch_fullscreen
= true;
668 osys
->is_fullscreen
= is_fullscreen
;
670 vlc_mutex_unlock(&osys
->lock
);
673 #if defined(_WIN32) || defined(__OS2__)
674 case VOUT_DISPLAY_EVENT_WINDOW_STATE
: {
675 const unsigned state
= va_arg(args
, unsigned);
677 msg_Dbg(vd
, "VoutDisplayEvent 'window state' %u", state
);
679 vlc_mutex_lock(&osys
->lock
);
680 if (state
!= osys
->wm_state
) {
681 osys
->ch_wm_state
= true;
682 osys
->wm_state
= state
;
684 vlc_mutex_unlock(&osys
->lock
);
688 case VOUT_DISPLAY_EVENT_DISPLAY_SIZE
: {
689 const int width
= (int)va_arg(args
, int);
690 const int height
= (int)va_arg(args
, int);
691 msg_Dbg(vd
, "VoutDisplayEvent 'resize' %dx%d", width
, height
);
694 vlc_mutex_lock(&osys
->lock
);
696 osys
->ch_display_size
= true;
697 osys
->display_width
= width
;
698 osys
->display_height
= height
;
700 vlc_mutex_unlock(&osys
->lock
);
704 case VOUT_DISPLAY_EVENT_PICTURES_INVALID
: {
705 msg_Warn(vd
, "VoutDisplayEvent 'pictures invalid'");
708 assert(vd
->info
.has_pictures_invalid
);
710 vlc_mutex_lock(&osys
->lock
);
711 osys
->reset_pictures
= true;
712 vlc_mutex_unlock(&osys
->lock
);
716 msg_Err(vd
, "VoutDisplayEvent received event %d", event
);
717 /* TODO add an assert when all event are handled */
722 static vout_window_t
*VoutDisplayNewWindow(vout_display_t
*vd
, unsigned type
)
724 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
725 vout_window_t
*window
= vout_NewDisplayWindow(osys
->vout
, type
);
727 vout_display_window_Attach(window
, vd
);
731 static void VoutDisplayDelWindow(vout_display_t
*vd
, vout_window_t
*window
)
733 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
736 vout_display_window_Detach(window
);
737 vout_DeleteDisplayWindow(osys
->vout
, window
);
740 static void VoutDisplayFitWindow(vout_display_t
*vd
, bool default_size
)
742 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
743 vout_display_cfg_t cfg
= osys
->cfg
;
745 if (!cfg
.is_display_filled
)
748 cfg
.display
.width
= 0;
750 cfg
.display
.height
= 0;
752 cfg
.display
.height
= osys
->height_saved
;
757 unsigned display_width
;
758 unsigned display_height
;
759 vout_display_GetDefaultDisplaySize(&display_width
, &display_height
,
761 vout_SetDisplayWindowSize(osys
->vout
, display_width
, display_height
);
764 static void VoutDisplayCropRatio(int *left
, int *top
, int *right
, int *bottom
,
765 const video_format_t
*source
,
766 unsigned num
, unsigned den
)
768 unsigned scaled_width
= (uint64_t)source
->i_visible_height
* num
* source
->i_sar_den
/ den
/ source
->i_sar_num
;
769 unsigned scaled_height
= (uint64_t)source
->i_visible_width
* den
* source
->i_sar_num
/ num
/ source
->i_sar_den
;
771 if (scaled_width
< source
->i_visible_width
) {
772 *left
= (source
->i_visible_width
- scaled_width
) / 2;
774 *right
= *left
+ scaled_width
;
775 *bottom
= *top
+ source
->i_visible_height
;
778 *top
= (source
->i_visible_height
- scaled_height
) / 2;
779 *right
= *left
+ source
->i_visible_width
;
780 *bottom
= *top
+ scaled_height
;
784 bool vout_ManageDisplay(vout_display_t
*vd
, bool allow_reset_pictures
)
786 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
788 vout_display_Manage(vd
);
790 /* Handle mouse timeout */
791 const mtime_t date
= mdate();
792 bool hide_mouse
= false;
794 vlc_mutex_lock(&osys
->lock
);
796 if (!osys
->mouse
.is_hidden
&&
797 osys
->mouse
.last_moved
+ osys
->mouse
.hide_timeout
< date
) {
798 osys
->mouse
.is_hidden
= hide_mouse
= true;
799 } else if (osys
->mouse
.ch_activity
) {
800 osys
->mouse
.is_hidden
= false;
802 osys
->mouse
.ch_activity
= false;
803 vlc_mutex_unlock(&osys
->lock
);
806 if (!vd
->info
.has_hide_mouse
) {
807 msg_Dbg(vd
, "auto hiding mouse cursor");
808 vout_display_Control(vd
, VOUT_DISPLAY_HIDE_MOUSE
);
810 vout_SendEventMouseHidden(osys
->vout
);
813 bool reset_render
= false;
816 vlc_mutex_lock(&osys
->lock
);
818 bool ch_fullscreen
= osys
->ch_fullscreen
;
819 bool is_fullscreen
= osys
->is_fullscreen
;
820 osys
->ch_fullscreen
= false;
822 #if defined(_WIN32) || defined(__OS2__)
823 bool ch_wm_state
= osys
->ch_wm_state
;
824 unsigned wm_state
= osys
->wm_state
;
825 osys
->ch_wm_state
= false;
828 bool ch_display_size
= osys
->ch_display_size
;
829 int display_width
= osys
->display_width
;
830 int display_height
= osys
->display_height
;
831 osys
->ch_display_size
= false;
834 if (allow_reset_pictures
) {
835 reset_pictures
= osys
->reset_pictures
;
836 osys
->reset_pictures
= false;
838 reset_pictures
= false;
841 vlc_mutex_unlock(&osys
->lock
);
843 if (!ch_fullscreen
&&
846 !osys
->ch_display_filled
&&
848 #if defined(_WIN32) || defined(__OS2__)
854 if (!osys
->cfg
.is_fullscreen
&& osys
->fit_window
!= 0) {
855 VoutDisplayFitWindow(vd
, osys
->fit_window
== -1);
856 osys
->fit_window
= 0;
864 if (vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_FULLSCREEN
,
865 is_fullscreen
) == VLC_SUCCESS
) {
866 osys
->cfg
.is_fullscreen
= is_fullscreen
;
869 vout_SetDisplayWindowSize(osys
->vout
, osys
->width_saved
,
872 is_fullscreen
= osys
->cfg
.is_fullscreen
;
874 msg_Err(vd
, "Failed to set fullscreen");
879 if (ch_display_size
) {
880 vout_display_cfg_t cfg
= osys
->cfg
;
881 cfg
.display
.width
= display_width
;
882 cfg
.display
.height
= display_height
;
884 osys
->width_saved
= osys
->cfg
.display
.width
;
885 osys
->height_saved
= osys
->cfg
.display
.height
;
887 vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_DISPLAY_SIZE
, &cfg
);
889 osys
->cfg
.display
.width
= display_width
;
890 osys
->cfg
.display
.height
= display_height
;
893 if (osys
->ch_display_filled
) {
894 vout_display_cfg_t cfg
= osys
->cfg
;
896 cfg
.is_display_filled
= osys
->is_display_filled
;
898 if (vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_DISPLAY_FILLED
, &cfg
)) {
899 msg_Err(vd
, "Failed to change display filled state");
900 osys
->is_display_filled
= osys
->cfg
.is_display_filled
;
902 osys
->cfg
.is_display_filled
= osys
->is_display_filled
;
903 osys
->ch_display_filled
= false;
907 vout_display_cfg_t cfg
= osys
->cfg
;
909 cfg
.zoom
.num
= osys
->zoom
.num
;
910 cfg
.zoom
.den
= osys
->zoom
.den
;
912 if (10 * cfg
.zoom
.num
<= cfg
.zoom
.den
) {
915 } else if (cfg
.zoom
.num
>= 10 * cfg
.zoom
.den
) {
920 if (vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_ZOOM
, &cfg
)) {
921 msg_Err(vd
, "Failed to change zoom");
922 osys
->zoom
.num
= osys
->cfg
.zoom
.num
;
923 osys
->zoom
.den
= osys
->cfg
.zoom
.den
;
925 osys
->fit_window
= -1;
928 osys
->cfg
.zoom
.num
= osys
->zoom
.num
;
929 osys
->cfg
.zoom
.den
= osys
->zoom
.den
;
930 osys
->ch_zoom
= false;
932 #if defined(_WIN32) || defined(__OS2__)
935 if (vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_WINDOW_STATE
, wm_state
)) {
936 msg_Err(vd
, "Failed to set on top");
937 wm_state
= osys
->wm_state
;
939 osys
->wm_state_initial
= wm_state
;
944 video_format_t source
= vd
->source
;
946 if (osys
->sar
.num
> 0 && osys
->sar
.den
> 0) {
947 source
.i_sar_num
= osys
->sar
.num
;
948 source
.i_sar_den
= osys
->sar
.den
;
950 source
.i_sar_num
= osys
->source
.i_sar_num
;
951 source
.i_sar_den
= osys
->source
.i_sar_den
;
954 if (vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_SOURCE_ASPECT
, &source
)) {
955 /* There nothing much we can do. The only reason a vout display
956 * does not support it is because it need the core to add black border
957 * to the video for it.
958 * TODO add black borders ?
960 msg_Err(vd
, "Failed to change source AR");
962 } else if (!osys
->fit_window
) {
963 osys
->fit_window
= 1;
966 osys
->sar
.num
= source
.i_sar_num
;
967 osys
->sar
.den
= source
.i_sar_den
;
968 osys
->ch_sar
= false;
970 /* If a crop ratio is requested, recompute the parameters */
971 if (osys
->crop
.num
> 0 && osys
->crop
.den
> 0)
972 osys
->ch_crop
= true;
976 video_format_t source
= vd
->source
;
978 unsigned crop_num
= osys
->crop
.num
;
979 unsigned crop_den
= osys
->crop
.den
;
980 if (crop_num
> 0 && crop_den
> 0) {
981 video_format_t fmt
= osys
->source
;
982 fmt
.i_sar_num
= source
.i_sar_num
;
983 fmt
.i_sar_den
= source
.i_sar_den
;
984 VoutDisplayCropRatio(&osys
->crop
.left
, &osys
->crop
.top
,
985 &osys
->crop
.right
, &osys
->crop
.bottom
,
986 &fmt
, crop_num
, crop_den
);
988 const int right_max
= osys
->source
.i_x_offset
+ osys
->source
.i_visible_width
;
989 const int bottom_max
= osys
->source
.i_y_offset
+ osys
->source
.i_visible_height
;
990 int left
= VLC_CLIP((int)osys
->source
.i_x_offset
+ osys
->crop
.left
,
992 int top
= VLC_CLIP((int)osys
->source
.i_y_offset
+ osys
->crop
.top
,
995 if (osys
->crop
.right
<= 0)
996 right
= (int)(osys
->source
.i_x_offset
+ osys
->source
.i_visible_width
) + osys
->crop
.right
;
998 right
= (int)osys
->source
.i_x_offset
+ osys
->crop
.right
;
999 right
= VLC_CLIP(right
, left
+ 1, right_max
);
1000 if (osys
->crop
.bottom
<= 0)
1001 bottom
= (int)(osys
->source
.i_y_offset
+ osys
->source
.i_visible_height
) + osys
->crop
.bottom
;
1003 bottom
= (int)osys
->source
.i_y_offset
+ osys
->crop
.bottom
;
1004 bottom
= VLC_CLIP(bottom
, top
+ 1, bottom_max
);
1006 source
.i_x_offset
= left
;
1007 source
.i_y_offset
= top
;
1008 source
.i_visible_width
= right
- left
;
1009 source
.i_visible_height
= bottom
- top
;
1010 video_format_Print(VLC_OBJECT(vd
), "SOURCE ", &osys
->source
);
1011 video_format_Print(VLC_OBJECT(vd
), "CROPPED", &source
);
1012 if (vout_display_Control(vd
, VOUT_DISPLAY_CHANGE_SOURCE_CROP
, &source
)) {
1013 msg_Err(vd
, "Failed to change source crop TODO implement crop at core");
1015 source
= vd
->source
;
1016 crop_num
= osys
->crop_saved
.num
;
1017 crop_den
= osys
->crop_saved
.den
;
1018 /* FIXME implement cropping in the core if not supported by the
1019 * vout module (easy)
1021 } else if (!osys
->fit_window
) {
1022 osys
->fit_window
= 1;
1024 vd
->source
= source
;
1025 osys
->crop
.left
= source
.i_x_offset
- osys
->source
.i_x_offset
;
1026 osys
->crop
.top
= source
.i_y_offset
- osys
->source
.i_y_offset
;
1027 /* FIXME for right/bottom we should keep the 'type' border vs window */
1028 osys
->crop
.right
= (source
.i_x_offset
+ source
.i_visible_width
) -
1029 (osys
->source
.i_x_offset
+ osys
->source
.i_visible_width
);
1030 osys
->crop
.bottom
= (source
.i_y_offset
+ source
.i_visible_height
) -
1031 (osys
->source
.i_y_offset
+ osys
->source
.i_visible_height
);
1032 osys
->crop
.num
= crop_num
;
1033 osys
->crop
.den
= crop_den
;
1034 osys
->ch_crop
= false;
1038 if (reset_pictures
) {
1039 if (vout_display_Control(vd
, VOUT_DISPLAY_RESET_PICTURES
)) {
1040 /* FIXME what to do here ? */
1041 msg_Err(vd
, "Failed to reset pictures (probably fatal)");
1043 reset_render
= true;
1047 VoutDisplayResetRender(vd
);
1049 return reset_render
;
1052 bool vout_AreDisplayPicturesInvalid(vout_display_t
*vd
)
1054 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1056 vlc_mutex_lock(&osys
->lock
);
1057 const bool reset_pictures
= osys
->reset_pictures
;
1058 vlc_mutex_unlock(&osys
->lock
);
1060 return reset_pictures
;
1063 bool vout_IsDisplayFiltered(vout_display_t
*vd
)
1065 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1067 return osys
->filters
!= NULL
;
1070 picture_t
*vout_FilterDisplay(vout_display_t
*vd
, picture_t
*picture
)
1072 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1074 assert(osys
->filters
);
1075 if (filter_chain_GetLength(osys
->filters
) <= 0) {
1076 picture_Release(picture
);
1079 return filter_chain_VideoFilter(osys
->filters
, picture
);
1082 void vout_UpdateDisplaySourceProperties(vout_display_t
*vd
, const video_format_t
*source
)
1084 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1086 if (source
->i_sar_num
* osys
->source
.i_sar_den
!=
1087 source
->i_sar_den
* osys
->source
.i_sar_num
) {
1089 osys
->source
.i_sar_num
= source
->i_sar_num
;
1090 osys
->source
.i_sar_den
= source
->i_sar_den
;
1091 vlc_ureduce(&osys
->source
.i_sar_num
, &osys
->source
.i_sar_den
,
1092 osys
->source
.i_sar_num
, osys
->source
.i_sar_den
, 0);
1094 /* FIXME it will override any AR that the user would have forced */
1095 osys
->ch_sar
= true;
1096 osys
->sar
.num
= osys
->source
.i_sar_num
;
1097 osys
->sar
.den
= osys
->source
.i_sar_den
;
1099 if (source
->i_x_offset
!= osys
->source
.i_x_offset
||
1100 source
->i_y_offset
!= osys
->source
.i_y_offset
||
1101 source
->i_visible_width
!= osys
->source
.i_visible_width
||
1102 source
->i_visible_height
!= osys
->source
.i_visible_height
) {
1104 video_format_CopyCrop(&osys
->source
, source
);
1106 /* Force the vout to reapply the current user crop settings over the new decoder
1108 osys
->ch_crop
= true;
1112 void vout_SetDisplayFullscreen(vout_display_t
*vd
, bool is_fullscreen
)
1114 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1116 vlc_mutex_lock(&osys
->lock
);
1117 if (!osys
->is_fullscreen
!= !is_fullscreen
) {
1118 osys
->ch_fullscreen
= true;
1119 osys
->is_fullscreen
= is_fullscreen
;
1121 vlc_mutex_unlock(&osys
->lock
);
1124 void vout_SetDisplayFilled(vout_display_t
*vd
, bool is_filled
)
1126 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1128 if (!osys
->is_display_filled
!= !is_filled
) {
1129 osys
->ch_display_filled
= true;
1130 osys
->is_display_filled
= is_filled
;
1134 void vout_SetDisplayZoom(vout_display_t
*vd
, unsigned num
, unsigned den
)
1136 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1138 if (num
> 0 && den
> 0) {
1139 vlc_ureduce(&num
, &den
, num
, den
, 0);
1145 if (osys
->is_display_filled
||
1146 osys
->zoom
.num
!= num
|| osys
->zoom
.den
!= den
) {
1147 osys
->ch_zoom
= true;
1148 osys
->zoom
.num
= num
;
1149 osys
->zoom
.den
= den
;
1153 void vout_SetDisplayAspect(vout_display_t
*vd
, unsigned dar_num
, unsigned dar_den
)
1155 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1157 unsigned sar_num
, sar_den
;
1158 if (dar_num
> 0 && dar_den
> 0) {
1159 sar_num
= dar_num
* osys
->source
.i_visible_height
;
1160 sar_den
= dar_den
* osys
->source
.i_visible_width
;
1161 vlc_ureduce(&sar_num
, &sar_den
, sar_num
, sar_den
, 0);
1167 if (osys
->sar
.num
!= sar_num
|| osys
->sar
.den
!= sar_den
) {
1168 osys
->ch_sar
= true;
1169 osys
->sar
.num
= sar_num
;
1170 osys
->sar
.den
= sar_den
;
1173 void vout_SetDisplayCrop(vout_display_t
*vd
,
1174 unsigned crop_num
, unsigned crop_den
,
1175 unsigned left
, unsigned top
, int right
, int bottom
)
1177 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1179 if (osys
->crop
.left
!= (int)left
|| osys
->crop
.top
!= (int)top
||
1180 osys
->crop
.right
!= right
|| osys
->crop
.bottom
!= bottom
||
1181 (crop_num
> 0 && crop_den
> 0 &&
1182 (crop_num
!= osys
->crop
.num
|| crop_den
!= osys
->crop
.den
))) {
1184 osys
->crop
.left
= left
;
1185 osys
->crop
.top
= top
;
1186 osys
->crop
.right
= right
;
1187 osys
->crop
.bottom
= bottom
;
1188 osys
->crop
.num
= crop_num
;
1189 osys
->crop
.den
= crop_den
;
1191 osys
->ch_crop
= true;
1195 static vout_display_t
*DisplayNew(vout_thread_t
*vout
,
1196 const video_format_t
*source
,
1197 const vout_display_state_t
*state
,
1199 bool is_wrapper
, vout_display_t
*wrapper
,
1200 mtime_t double_click_timeout
,
1201 mtime_t hide_timeout
,
1202 const vout_display_owner_t
*owner_ptr
)
1205 vout_display_owner_sys_t
*osys
= calloc(1, sizeof(*osys
));
1206 vout_display_cfg_t
*cfg
= &osys
->cfg
;
1209 osys
->sar_initial
.num
= state
->sar
.num
;
1210 osys
->sar_initial
.den
= state
->sar
.den
;
1211 vout_display_GetDefaultDisplaySize(&cfg
->display
.width
, &cfg
->display
.height
,
1215 osys
->is_wrapper
= is_wrapper
;
1216 osys
->wrapper
= wrapper
;
1218 vlc_mutex_init(&osys
->lock
);
1220 vlc_mouse_Init(&osys
->mouse
.state
);
1221 osys
->mouse
.last_moved
= mdate();
1222 osys
->mouse
.double_click_timeout
= double_click_timeout
;
1223 osys
->mouse
.hide_timeout
= hide_timeout
;
1224 osys
->is_fullscreen
= cfg
->is_fullscreen
;
1225 osys
->display_width
= cfg
->display
.width
;
1226 osys
->display_height
= cfg
->display
.height
;
1227 osys
->is_display_filled
= cfg
->is_display_filled
;
1228 osys
->width_saved
= cfg
->display
.width
;
1229 osys
->height_saved
= cfg
->display
.height
;
1230 if (osys
->is_fullscreen
) {
1231 vout_display_cfg_t cfg_windowed
= *cfg
;
1232 cfg_windowed
.is_fullscreen
= false;
1233 cfg_windowed
.display
.width
= 0;
1234 cfg_windowed
.display
.height
= 0;
1235 vout_display_GetDefaultDisplaySize(&osys
->width_saved
,
1236 &osys
->height_saved
,
1237 source
, &cfg_windowed
);
1240 osys
->zoom
.num
= cfg
->zoom
.num
;
1241 osys
->zoom
.den
= cfg
->zoom
.den
;
1242 #if defined(_WIN32) || defined(__OS2__)
1243 osys
->wm_state_initial
= VOUT_WINDOW_STATE_NORMAL
;
1244 osys
->wm_state
= state
->wm_state
;
1245 osys
->ch_wm_state
= true;
1247 osys
->fit_window
= 0;
1248 osys
->event
.fifo
= NULL
;
1250 osys
->source
= *source
;
1251 osys
->crop
.left
= 0;
1253 osys
->crop
.right
= 0;
1254 osys
->crop
.bottom
= 0;
1255 osys
->crop_saved
.num
= 0;
1256 osys
->crop_saved
.den
= 0;
1260 osys
->sar
.num
= osys
->sar_initial
.num
? osys
->sar_initial
.num
: source
->i_sar_num
;
1261 osys
->sar
.den
= osys
->sar_initial
.den
? osys
->sar_initial
.den
: source
->i_sar_den
;
1263 vout_display_owner_t owner
;
1267 owner
.event
= VoutDisplayEvent
;
1268 owner
.window_new
= VoutDisplayNewWindow
;
1269 owner
.window_del
= VoutDisplayDelWindow
;
1273 vout_display_t
*p_display
= vout_display_New(VLC_OBJECT(vout
),
1274 module
, !is_wrapper
,
1275 source
, cfg
, &owner
);
1279 if (VoutDisplayCreateRender(p_display
)) {
1280 vout_display_Delete(p_display
);
1284 /* Setup delayed request */
1285 if (osys
->sar
.num
!= source
->i_sar_num
||
1286 osys
->sar
.den
!= source
->i_sar_den
)
1287 osys
->ch_sar
= true;
1291 vlc_mutex_destroy(&osys
->lock
);
1296 void vout_DeleteDisplay(vout_display_t
*vd
, vout_display_state_t
*state
)
1298 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1301 if (!osys
->is_wrapper
)
1302 state
->cfg
= osys
->cfg
;
1303 #if defined(_WIN32) || defined(__OS2__)
1304 state
->wm_state
= osys
->wm_state
;
1306 state
->sar
.num
= osys
->sar_initial
.num
;
1307 state
->sar
.den
= osys
->sar_initial
.den
;
1310 VoutDisplayDestroyRender(vd
);
1311 if (osys
->is_wrapper
)
1313 vout_display_Delete(vd
);
1314 if (osys
->event
.fifo
) {
1315 vlc_cancel(osys
->event
.thread
);
1316 vlc_join(osys
->event
.thread
, NULL
);
1317 block_FifoRelease(osys
->event
.fifo
);
1319 vlc_mutex_destroy(&osys
->lock
);
1323 /*****************************************************************************
1325 *****************************************************************************/
1326 vout_display_t
*vout_NewDisplay(vout_thread_t
*vout
,
1327 const video_format_t
*source
,
1328 const vout_display_state_t
*state
,
1330 mtime_t double_click_timeout
,
1331 mtime_t hide_timeout
)
1333 return DisplayNew(vout
, source
, state
, module
, false, NULL
,
1334 double_click_timeout
, hide_timeout
, NULL
);
1337 /*****************************************************************************
1339 *****************************************************************************/
1340 struct vout_display_sys_t
{
1341 picture_pool_t
*pool
;
1342 video_splitter_t
*splitter
;
1346 picture_t
**picture
;
1347 vout_display_t
**display
;
1349 struct video_splitter_owner_t
{
1350 vout_display_t
*wrapper
;
1353 static vout_window_t
*SplitterNewWindow(vout_display_t
*vd
, unsigned type
)
1355 vout_display_owner_sys_t
*osys
= vd
->owner
.sys
;
1356 vout_window_t
*window
;
1357 vout_window_cfg_t cfg
= {
1359 .width
= vd
->cfg
->display
.width
,
1360 .height
= vd
->cfg
->display
.height
,
1361 .is_standalone
= true,
1364 window
= vout_display_window_New(osys
->vout
, &cfg
);
1366 vout_display_window_Attach(window
, vd
);
1370 static void SplitterDelWindow(vout_display_t
*vd
, vout_window_t
*window
)
1372 if (window
!= NULL
) {
1373 vout_display_window_Detach(window
);
1374 vout_display_window_Delete(window
);
1379 static void SplitterEvent(vout_display_t
*vd
, int event
, va_list args
)
1381 //vout_display_owner_sys_t *osys = vd->owner.sys;
1385 case VOUT_DISPLAY_EVENT_MOUSE_STATE
:
1386 case VOUT_DISPLAY_EVENT_MOUSE_MOVED
:
1387 case VOUT_DISPLAY_EVENT_MOUSE_PRESSED
:
1388 case VOUT_DISPLAY_EVENT_MOUSE_RELEASED
:
1392 case VOUT_DISPLAY_EVENT_MOUSE_DOUBLE_CLICK
:
1393 case VOUT_DISPLAY_EVENT_KEY
:
1394 case VOUT_DISPLAY_EVENT_CLOSE
:
1395 case VOUT_DISPLAY_EVENT_FULLSCREEN
:
1396 case VOUT_DISPLAY_EVENT_DISPLAY_SIZE
:
1397 case VOUT_DISPLAY_EVENT_PICTURES_INVALID
:
1398 VoutDisplayEvent(vd
, event
, args
);
1402 msg_Err(vd
, "splitter event not implemented: %d", event
);
1407 static picture_pool_t
*SplitterPool(vout_display_t
*vd
, unsigned count
)
1409 vout_display_sys_t
*sys
= vd
->sys
;
1411 sys
->pool
= picture_pool_NewFromFormat(&vd
->fmt
, count
);
1414 static void SplitterPrepare(vout_display_t
*vd
,
1416 subpicture_t
*subpicture
)
1418 vout_display_sys_t
*sys
= vd
->sys
;
1420 picture_Hold(picture
);
1421 assert(!subpicture
);
1423 if (video_splitter_Filter(sys
->splitter
, sys
->picture
, picture
)) {
1424 for (int i
= 0; i
< sys
->count
; i
++)
1425 sys
->picture
[i
] = NULL
;
1426 picture_Release(picture
);
1430 for (int i
= 0; i
< sys
->count
; i
++) {
1431 if (vout_IsDisplayFiltered(sys
->display
[i
]))
1432 sys
->picture
[i
] = vout_FilterDisplay(sys
->display
[i
], sys
->picture
[i
]);
1433 if (sys
->picture
[i
])
1434 vout_display_Prepare(sys
->display
[i
], sys
->picture
[i
], NULL
);
1437 static void SplitterDisplay(vout_display_t
*vd
,
1439 subpicture_t
*subpicture
)
1441 vout_display_sys_t
*sys
= vd
->sys
;
1443 assert(!subpicture
);
1444 for (int i
= 0; i
< sys
->count
; i
++) {
1445 if (sys
->picture
[i
])
1446 vout_display_Display(sys
->display
[i
], sys
->picture
[i
], NULL
);
1448 picture_Release(picture
);
1450 static int SplitterControl(vout_display_t
*vd
, int query
, va_list args
)
1452 (void)vd
; (void)query
; (void)args
;
1453 return VLC_EGENERIC
;
1455 static void SplitterManage(vout_display_t
*vd
)
1457 vout_display_sys_t
*sys
= vd
->sys
;
1459 for (int i
= 0; i
< sys
->count
; i
++)
1460 vout_ManageDisplay(sys
->display
[i
], true);
1463 static int SplitterPictureNew(video_splitter_t
*splitter
, picture_t
*picture
[])
1465 vout_display_sys_t
*wsys
= splitter
->p_owner
->wrapper
->sys
;
1467 for (int i
= 0; i
< wsys
->count
; i
++) {
1468 if (vout_IsDisplayFiltered(wsys
->display
[i
])) {
1469 /* TODO use a pool ? */
1470 picture
[i
] = picture_NewFromFormat(&wsys
->display
[i
]->source
);
1472 picture_pool_t
*pool
= vout_display_Pool(wsys
->display
[i
], 1);
1473 picture
[i
] = pool
? picture_pool_Get(pool
) : NULL
;
1476 for (int j
= 0; j
< i
; j
++)
1477 picture_Release(picture
[j
]);
1478 return VLC_EGENERIC
;
1483 static void SplitterPictureDel(video_splitter_t
*splitter
, picture_t
*picture
[])
1485 vout_display_sys_t
*wsys
= splitter
->p_owner
->wrapper
->sys
;
1487 for (int i
= 0; i
< wsys
->count
; i
++)
1488 picture_Release(picture
[i
]);
1490 static void SplitterClose(vout_display_t
*vd
)
1492 vout_display_sys_t
*sys
= vd
->sys
;
1495 video_splitter_t
*splitter
= sys
->splitter
;
1496 free(splitter
->p_owner
);
1497 video_splitter_Delete(splitter
);
1500 picture_pool_Release(sys
->pool
);
1503 for (int i
= 0; i
< sys
->count
; i
++)
1504 vout_DeleteDisplay(sys
->display
[i
], NULL
);
1505 TAB_CLEAN(sys
->count
, sys
->display
);
1511 vout_display_t
*vout_NewSplitter(vout_thread_t
*vout
,
1512 const video_format_t
*source
,
1513 const vout_display_state_t
*state
,
1515 const char *splitter_module
,
1516 mtime_t double_click_timeout
,
1517 mtime_t hide_timeout
)
1519 video_splitter_t
*splitter
=
1520 video_splitter_New(VLC_OBJECT(vout
), splitter_module
, source
);
1525 vout_display_t
*wrapper
=
1526 DisplayNew(vout
, source
, state
, module
, true, NULL
,
1527 double_click_timeout
, hide_timeout
, NULL
);
1529 video_splitter_Delete(splitter
);
1532 vout_display_sys_t
*sys
= malloc(sizeof(*sys
));
1535 sys
->picture
= calloc(splitter
->i_output
, sizeof(*sys
->picture
));
1538 sys
->splitter
= splitter
;
1541 wrapper
->pool
= SplitterPool
;
1542 wrapper
->prepare
= SplitterPrepare
;
1543 wrapper
->display
= SplitterDisplay
;
1544 wrapper
->control
= SplitterControl
;
1545 wrapper
->manage
= SplitterManage
;
1549 video_splitter_owner_t
*vso
= xmalloc(sizeof(*vso
));
1550 vso
->wrapper
= wrapper
;
1551 splitter
->p_owner
= vso
;
1552 splitter
->pf_picture_new
= SplitterPictureNew
;
1553 splitter
->pf_picture_del
= SplitterPictureDel
;
1556 TAB_INIT(sys
->count
, sys
->display
);
1557 for (int i
= 0; i
< splitter
->i_output
; i
++) {
1558 vout_display_owner_t vdo
= {
1559 .event
= SplitterEvent
,
1560 .window_new
= SplitterNewWindow
,
1561 .window_del
= SplitterDelWindow
,
1563 const video_splitter_output_t
*output
= &splitter
->p_output
[i
];
1564 vout_display_state_t ostate
;
1566 memset(&ostate
, 0, sizeof(ostate
));
1567 ostate
.cfg
.is_fullscreen
= false;
1568 ostate
.cfg
.display
= state
->cfg
.display
;
1569 ostate
.cfg
.align
.horizontal
= 0; /* TODO */
1570 ostate
.cfg
.align
.vertical
= 0; /* TODO */
1571 ostate
.cfg
.is_display_filled
= true;
1572 ostate
.cfg
.zoom
.num
= 1;
1573 ostate
.cfg
.zoom
.den
= 1;
1575 vout_display_t
*vd
= DisplayNew(vout
, &output
->fmt
, &ostate
,
1576 output
->psz_module
? output
->psz_module
: module
,
1578 double_click_timeout
, hide_timeout
, &vdo
);
1580 vout_DeleteDisplay(wrapper
, NULL
);
1583 TAB_APPEND(sys
->count
, sys
->display
, vd
);
1589 /*****************************************************************************
1591 *****************************************************************************/
1592 #include "vout_internal.h"
1593 void vout_SendDisplayEventMouse(vout_thread_t
*vout
, const vlc_mouse_t
*m
)
1595 vlc_mouse_t tmp1
, tmp2
;
1597 /* The check on spu is needed as long as ALLOW_DUMMY_VOUT is defined */
1598 if (vout
->p
->spu
&& spu_ProcessMouse( vout
->p
->spu
, m
, &vout
->p
->display
.vd
->source
))
1601 vlc_mutex_lock( &vout
->p
->filter
.lock
);
1602 if (vout
->p
->filter
.chain_static
&& vout
->p
->filter
.chain_interactive
) {
1603 if (!filter_chain_MouseFilter(vout
->p
->filter
.chain_interactive
, &tmp1
, m
))
1605 if (!filter_chain_MouseFilter(vout
->p
->filter
.chain_static
, &tmp2
, m
))
1608 vlc_mutex_unlock( &vout
->p
->filter
.lock
);
1610 if (vlc_mouse_HasMoved(&vout
->p
->mouse
, m
)) {
1611 vout_SendEventMouseMoved(vout
, m
->i_x
, m
->i_y
);
1613 if (vlc_mouse_HasButton(&vout
->p
->mouse
, m
)) {
1614 for (unsigned button
= 0; button
< MOUSE_BUTTON_MAX
; button
++) {
1615 if (vlc_mouse_HasPressed(&vout
->p
->mouse
, m
, button
))
1616 vout_SendEventMousePressed(vout
, button
);
1617 else if (vlc_mouse_HasReleased(&vout
->p
->mouse
, m
, button
))
1618 vout_SendEventMouseReleased(vout
, button
);
1621 if (m
->b_double_click
)
1622 vout_SendEventMouseDoubleClick(vout
);
1623 vout
->p
->mouse
= *m
;