qt: playlist: use item title if available
[vlc.git] / modules / video_output / splitter.c
blob9a2a1544e7cac376c55aaf928bd5bc13f3e9e324
1 /**
2 * @file splitter.c
3 * @brief Video splitter video output module for VLC media player
4 */
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 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
28 #include <assert.h>
29 #include <stdlib.h>
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;
41 vlc_sem_t lock;
42 unsigned width;
43 unsigned height;
46 struct vout_display_sys_t {
47 video_splitter_t splitter;
48 vlc_mutex_t lock;
50 picture_t **pictures;
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;
59 picture_Hold(pic);
60 (void) subpic;
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;
68 return;
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);
93 (void) picture;
96 static int vlc_vidsplit_Control(vout_display_t *vd, int query)
98 (void) vd;
100 switch (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:
106 return VLC_SUCCESS;
108 return VLC_EGENERIC;
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);
125 if (display != NULL)
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);
144 part->width = width;
145 part->height = height;
147 if (part->display != NULL)
148 vout_display_SetSize(part->display, width, height);
150 if (cb != NULL)
151 cb(wnd, opaque);
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);
165 if (display != NULL)
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,
179 &ev) == VLC_SUCCESS)
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,
210 .sys = sys,
213 vout_display_GetDefaultDisplaySize(&cfg.width, &cfg.height, source,
214 vdcfg);
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);
220 window = NULL;
223 return 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))
237 return VLC_EGENERIC;
239 char *name = var_InheritString(obj, "video-splitter");
240 if (name == NULL)
241 return VLC_EGENERIC;
243 vout_display_sys_t *sys = vlc_object_create(obj, sizeof (*sys));
244 if (unlikely(sys == NULL)) {
245 free(name);
246 return VLC_ENOMEM;
248 vd->sys = sys;
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);
256 free(name);
257 if (splitter->p_module == NULL) {
258 video_format_Clean(&splitter->fmt);
259 vlc_object_delete(splitter);
260 return VLC_EGENERIC;
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);
270 return VLC_ENOMEM;
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,
279 .zoom = { 1, 1 },
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;
286 part->width = 1;
287 part->height = 1;
289 part->window = video_splitter_CreateWindow(obj, &vdcfg, &output->fmt,
290 part);
291 if (part->window == NULL) {
292 splitter->i_output = i;
293 vlc_vidsplit_Close(vd);
294 return VLC_EGENERIC;
297 vdcfg.window = part->window;
298 vout_display_t *display = vout_display_New(obj, &output->fmt, ctx, &vdcfg,
299 modname, NULL);
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);
305 return VLC_EGENERIC;
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);
314 vd->ops = &ops;
315 (void) fmtp;
316 return VLC_SUCCESS;
319 vlc_module_begin()
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"))
327 vlc_module_end()