1 /*****************************************************************************
2 * flaschentaschen.c: Flaschen-Taschen video output display for vlc
3 * cf. https://github.com/hzeller/flaschen-taschen
4 *****************************************************************************
5 * Copyright (C) 2000-2009 VLC authors and VideoLAN
6 * Copyright (C) 2016 François Revol <revol@free.fr>
8 * Includes code from vdummy.c and aa.c:
9 * Authors: Samuel Hocevar <sam@zoy.org>
10 * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
40 #include <vlc_common.h>
42 #include <vlc_network.h>
43 #include <vlc_plugin.h>
44 #include <vlc_vout_display.h>
46 #define T_FLDISPLAY N_("Flaschen-Taschen display address")
47 #define LT_FLDISPLAY N_( \
48 "IP address or hostname of the Flaschen-Taschen display. " \
49 "Something like ft.noise or ftkleine.noise")
51 #define T_WIDTH N_("Width")
52 #define LT_WIDTH N_("Video width")
54 #define T_HEIGHT N_("Height")
55 #define LT_HEIGHT N_("Video height")
57 static int Open( vlc_object_t
* );
58 static void Close( vlc_object_t
* );
61 set_shortname( N_("Flaschen") )
62 set_description( N_("Flaschen-Taschen video output") )
63 set_capability( "vout display", 0 )
64 set_callbacks( Open
, Close
)
65 add_shortcut( "flaschen" )
67 set_category( CAT_VIDEO
)
68 set_subcategory( SUBCAT_VIDEO_VOUT
)
69 add_string( "flaschen-display", NULL
, T_FLDISPLAY
, LT_FLDISPLAY
, true )
70 add_integer("flaschen-width", 25, T_WIDTH
, LT_WIDTH
, false)
71 add_integer("flaschen-height", 20, T_HEIGHT
, LT_HEIGHT
, false)
75 /*****************************************************************************
77 *****************************************************************************/
78 struct vout_display_sys_t
{
83 static picture_pool_t
*Pool(vout_display_t
*, unsigned count
);
84 static void Display(vout_display_t
*, picture_t
*, subpicture_t
*);
85 static int Control(vout_display_t
*, int, va_list);
87 /*****************************************************************************
88 * Open: activates flaschen vout display method
89 *****************************************************************************/
90 static int Open(vlc_object_t
*object
)
92 vout_display_t
*vd
= (vout_display_t
*)object
;
93 vout_display_sys_t
*sys
;
97 vd
->sys
= sys
= calloc(1, sizeof(*sys
));
104 video_format_t fmt
= vd
->fmt
;
105 fmt
.i_chroma
= VLC_CODEC_RGB24
;
106 /* TODO: check if this works on big-endian systems */
107 fmt
.i_rmask
= 0xff0000;
108 fmt
.i_gmask
= 0x00ff00;
109 fmt
.i_bmask
= 0x0000ff;
110 fmt
.i_width
= var_InheritInteger(vd
, "flaschen-width");
111 fmt
.i_height
= var_InheritInteger(vd
, "flaschen-height");
112 fmt
.i_visible_width
= fmt
.i_width
;
113 fmt
.i_visible_height
= fmt
.i_height
;
115 /* p_vd->info is not modified */
117 char *display
= var_InheritString(vd
, "flaschen-display");
118 if (display
== NULL
) {
119 msg_Err(vd
, "missing flaschen-display");
123 msg_Dbg(vd
, "using display at %s (%dx%d)", display
, fmt
.i_width
, fmt
.i_height
);
125 fd
= net_ConnectDgram( vd
, display
, port
, -1, IPPROTO_UDP
);
130 "cannot create UDP socket for %s port %u",
139 /* Ignore any unexpected incoming packet */
140 setsockopt (fd
, SOL_SOCKET
, SO_RCVBUF
, &(int){ 0 }, sizeof (int));
147 vd
->display
= Display
;
148 vd
->control
= Control
;
151 vout_display_DeleteWindow(vd
, NULL
);
156 static void Close(vlc_object_t
*object
)
158 vout_display_t
*vd
= (vout_display_t
*)object
;
159 vout_display_sys_t
*sys
= vd
->sys
;
162 picture_pool_Release(sys
->pool
);
168 static picture_pool_t
*Pool(vout_display_t
*vd
, unsigned count
)
170 vout_display_sys_t
*sys
= vd
->sys
;
172 sys
->pool
= picture_pool_NewFromFormat(&vd
->fmt
, count
);
176 static void Display(vout_display_t
*vd
, picture_t
*picture
, subpicture_t
*subpicture
)
179 const long iovmax
= IOV_MAX
;
181 const long iovmax
= sysconf(_SC_IOV_MAX
);
183 vout_display_sys_t
*sys
= vd
->sys
;
185 VLC_UNUSED(subpicture
);
188 int header_len
= snprintf(buffer
, sizeof(buffer
), "P6\n%d %d\n255\n",
189 vd
->fmt
.i_width
, vd
->fmt
.i_height
);
190 /* TODO: support offset_{x,y,z}? (#FT:...) */
191 /* Note the protocol doesn't include any picture order field. */
192 /* (maybe add as comment?) */
194 int iovcnt
= 1 + vd
->fmt
.i_height
;
195 if (unlikely(iovcnt
> iovmax
))
198 struct iovec iov
[iovcnt
];
199 iov
[0].iov_base
= buffer
;
200 iov
[0].iov_len
= header_len
;
202 uint8_t *src
= picture
->p
->p_pixels
;
203 for (int i
= 1; i
< iovcnt
; i
++)
205 iov
[i
].iov_base
= src
;
206 iov
[i
].iov_len
= vd
->fmt
.i_width
* 3;
207 src
+= picture
->p
->i_pitch
;
210 struct msghdr hdr
= {
214 .msg_iovlen
= iovcnt
,
219 result
= sendmsg(sys
->fd
, &hdr
, 0);
221 msg_Err(vd
, "sendmsg: error %s in vout display flaschen", vlc_strerror_c(errno
));
222 else if (result
< (int)(header_len
+ vd
->fmt
.i_width
* vd
->fmt
.i_height
* 3))
223 msg_Err(vd
, "sendmsg only sent %d bytes in vout display flaschen", result
);
224 /* we might want to drop some frames? */
226 picture_Release(picture
);
230 * Control for vout display
232 static int Control(vout_display_t
*vd
, int query
, va_list args
)
237 case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE
:
238 case VOUT_DISPLAY_CHANGE_ZOOM
:
239 case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED
:
240 case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT
:
241 case VOUT_DISPLAY_CHANGE_FULLSCREEN
:
244 case VOUT_DISPLAY_HIDE_MOUSE
:
245 /* not really working */
249 msg_Err(vd
, "Unsupported query in vout display flaschen");