3 * @brief Video splitter video output module for VLC media player
5 /*****************************************************************************
6 * Copyright © 2009 Laurent Aimar
7 * Copyright © 2009-2018 Rémi Denis-Courmont
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 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_modules.h>
33 #include <vlc_plugin.h>
34 #include <vlc_codec.h>
35 #include <vlc_vout_display.h>
36 #include <vlc_video_splitter.h>
38 struct vlc_vidsplit_part
{
39 vout_window_t
*window
;
40 vout_display_t
*display
;
46 struct vout_display_sys_t
{
47 video_splitter_t splitter
;
51 struct vlc_vidsplit_part
*parts
;
54 static void vlc_vidsplit_Prepare(vout_display_t
*vd
, picture_t
*pic
,
55 subpicture_t
*subpic
, vlc_tick_t date
)
57 vout_display_sys_t
*sys
= vd
->sys
;
62 vlc_mutex_lock(&sys
->lock
);
63 if (video_splitter_Filter(&sys
->splitter
, sys
->pictures
, pic
)) {
64 vlc_mutex_unlock(&sys
->lock
);
66 for (int i
= 0; i
< sys
->splitter
.i_output
; i
++)
67 sys
->pictures
[i
] = NULL
;
70 vlc_mutex_unlock(&sys
->lock
);
72 for (int i
= 0; i
< sys
->splitter
.i_output
; i
++) {
73 struct vlc_vidsplit_part
*part
= &sys
->parts
[i
];
75 vlc_sem_wait(&part
->lock
);
76 sys
->pictures
[i
] = vout_display_Prepare(part
->display
,
77 sys
->pictures
[i
], NULL
, date
);
81 static void vlc_vidsplit_Display(vout_display_t
*vd
, picture_t
*picture
)
83 vout_display_sys_t
*sys
= vd
->sys
;
85 for (int i
= 0; i
< sys
->splitter
.i_output
; i
++) {
86 struct vlc_vidsplit_part
*part
= &sys
->parts
[i
];
88 if (sys
->pictures
[i
] != NULL
)
89 vout_display_Display(part
->display
, sys
->pictures
[i
]);
90 vlc_sem_post(&part
->lock
);
96 static int vlc_vidsplit_Control(vout_display_t
*vd
, int query
)
101 case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE
:
102 case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED
:
103 case VOUT_DISPLAY_CHANGE_ZOOM
:
104 case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT
:
105 case VOUT_DISPLAY_CHANGE_SOURCE_CROP
:
111 static void vlc_vidsplit_Close(vout_display_t
*vd
)
113 vout_display_sys_t
*sys
= vd
->sys
;
114 int n
= sys
->splitter
.i_output
;
116 for (int i
= 0; i
< n
; i
++) {
117 struct vlc_vidsplit_part
*part
= &sys
->parts
[i
];
118 vout_display_t
*display
;
120 vlc_sem_wait(&part
->lock
);
121 display
= part
->display
;
122 part
->display
= NULL
;
123 vlc_sem_post(&part
->lock
);
126 vout_display_Delete(display
);
128 vout_window_Disable(part
->window
);
129 vout_window_Delete(part
->window
);
132 module_unneed(&sys
->splitter
, sys
->splitter
.p_module
);
133 video_format_Clean(&sys
->splitter
.fmt
);
134 vlc_object_delete(&sys
->splitter
);
137 static void vlc_vidsplit_window_Resized(vout_window_t
*wnd
,
138 unsigned width
, unsigned height
,
139 vout_window_ack_cb cb
, void *opaque
)
141 struct vlc_vidsplit_part
*part
= wnd
->owner
.sys
;
143 vlc_sem_wait(&part
->lock
);
145 part
->height
= height
;
147 if (part
->display
!= NULL
)
148 vout_display_SetSize(part
->display
, width
, height
);
152 vlc_sem_post(&part
->lock
);
155 static void vlc_vidsplit_window_Closed(vout_window_t
*wnd
)
157 struct vlc_vidsplit_part
*part
= wnd
->owner
.sys
;
158 vout_display_t
*display
;
160 vlc_sem_wait(&part
->lock
);
161 display
= part
->display
;
162 part
->display
= NULL
;
163 vlc_sem_post(&part
->lock
);
166 vout_display_Delete(display
);
169 static void vlc_vidsplit_window_MouseEvent(vout_window_t
*wnd
,
170 const vout_window_mouse_event_t
*e
)
172 struct vlc_vidsplit_part
*part
= wnd
->owner
.sys
;
173 vout_display_t
*vd
= (vout_display_t
*)vlc_object_parent(wnd
);
174 vout_display_sys_t
*sys
= vd
->sys
;
175 vout_window_mouse_event_t ev
= *e
;
177 vlc_mutex_lock(&sys
->lock
);
178 if (video_splitter_Mouse(&sys
->splitter
, part
- sys
->parts
,
180 vout_window_SendMouseEvent(vd
->cfg
->window
, &ev
);
181 vlc_mutex_unlock(&sys
->lock
);
184 static void vlc_vidsplit_window_KeyboardEvent(vout_window_t
*wnd
, unsigned key
)
186 vout_display_t
*vd
= (vout_display_t
*)vlc_object_parent(wnd
);
187 vout_display_sys_t
*sys
= vd
->sys
;
189 vlc_mutex_lock(&sys
->lock
);
190 vout_window_ReportKeyPress(vd
->cfg
->window
, key
);
191 vlc_mutex_unlock(&sys
->lock
);
194 static const struct vout_window_callbacks vlc_vidsplit_window_cbs
= {
195 .resized
= vlc_vidsplit_window_Resized
,
196 .closed
= vlc_vidsplit_window_Closed
,
197 .mouse_event
= vlc_vidsplit_window_MouseEvent
,
198 .keyboard_event
= vlc_vidsplit_window_KeyboardEvent
,
201 static vout_window_t
*video_splitter_CreateWindow(vlc_object_t
*obj
,
202 const vout_display_cfg_t
*restrict vdcfg
,
203 const video_format_t
*restrict source
, void *sys
)
205 vout_window_cfg_t cfg
= {
206 .is_decorated
= true,
208 vout_window_owner_t owner
= {
209 .cbs
= &vlc_vidsplit_window_cbs
,
213 vout_display_GetDefaultDisplaySize(&cfg
.width
, &cfg
.height
, source
,
216 vout_window_t
*window
= vout_window_New(obj
, NULL
, &owner
);
217 if (window
!= NULL
) {
218 if (vout_window_Enable(window
, &cfg
)) {
219 vout_window_Delete(window
);
226 static const struct vlc_display_operations ops
= {
227 vlc_vidsplit_Close
, vlc_vidsplit_Prepare
, vlc_vidsplit_Display
, vlc_vidsplit_Control
, NULL
, NULL
,
230 static int vlc_vidsplit_Open(vout_display_t
*vd
,
231 const vout_display_cfg_t
*cfg
,
232 video_format_t
*fmtp
, vlc_video_context
*ctx
)
234 vlc_object_t
*obj
= VLC_OBJECT(vd
);
236 if (vout_display_cfg_IsWindowed(cfg
))
239 char *name
= var_InheritString(obj
, "video-splitter");
243 vout_display_sys_t
*sys
= vlc_object_create(obj
, sizeof (*sys
));
244 if (unlikely(sys
== NULL
)) {
250 video_splitter_t
*splitter
= &sys
->splitter
;
252 vlc_mutex_init(&sys
->lock
);
253 video_format_Copy(&splitter
->fmt
, vd
->source
);
255 splitter
->p_module
= module_need(splitter
, "video splitter", name
, true);
257 if (splitter
->p_module
== NULL
) {
258 video_format_Clean(&splitter
->fmt
);
259 vlc_object_delete(splitter
);
263 sys
->pictures
= vlc_obj_malloc(obj
, splitter
->i_output
264 * sizeof (*sys
->pictures
));
265 sys
->parts
= vlc_obj_malloc(obj
,
266 splitter
->i_output
* sizeof (*sys
->parts
));
267 if (unlikely(sys
->pictures
== NULL
|| sys
->parts
== NULL
)) {
268 splitter
->i_output
= 0;
269 vlc_vidsplit_Close(vd
);
273 for (int i
= 0; i
< splitter
->i_output
; i
++) {
274 const video_splitter_output_t
*output
= &splitter
->p_output
[i
];
275 vout_display_cfg_t vdcfg
= {
276 .display
= { 0, 0, { 1, 1 } },
277 .align
= { 0, 0 } /* TODO */,
278 .is_display_filled
= true,
281 const char *modname
= output
->psz_module
;
282 struct vlc_vidsplit_part
*part
= &sys
->parts
[i
];
284 vlc_sem_init(&part
->lock
, 1);
285 part
->display
= NULL
;
289 part
->window
= video_splitter_CreateWindow(obj
, &vdcfg
, &output
->fmt
,
291 if (part
->window
== NULL
) {
292 splitter
->i_output
= i
;
293 vlc_vidsplit_Close(vd
);
297 vdcfg
.window
= part
->window
;
298 vout_display_t
*display
= vout_display_New(obj
, &output
->fmt
, ctx
, &vdcfg
,
300 if (display
== NULL
) {
301 vout_window_Disable(part
->window
);
302 vout_window_Delete(part
->window
);
303 splitter
->i_output
= i
;
304 vlc_vidsplit_Close(vd
);
308 vlc_sem_wait(&part
->lock
);
309 part
->display
= display
;
310 vout_display_SetSize(display
, part
->width
, part
->height
);
311 vlc_sem_post(&part
->lock
);
320 set_shortname(N_("Splitter"))
321 set_description(N_("Video splitter display plugin"))
322 set_category(CAT_VIDEO
)
323 set_subcategory(SUBCAT_VIDEO_VOUT
)
324 set_callback_display(vlc_vidsplit_Open
, 0)
325 add_module("video-splitter", "video splitter", NULL
,
326 N_("Video splitter module"), N_("Video splitter module"))