opengl: factorize program creation
[vlc.git] / modules / video_output / flaschen.c
blob00e1e66a349e02a7fe93b28a3ddc4c0482a0cfe3
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 /*****************************************************************************
28 * Preamble
29 *****************************************************************************/
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
35 #include <errno.h>
36 #ifdef HAVE_SYS_UIO_H
37 # include <sys/uio.h>
38 #endif
40 #include <vlc_common.h>
41 #include <vlc_fs.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(vout_display_t *vd, const vout_display_cfg_t *cfg,
58 video_format_t *fmtp, vlc_video_context *context);
59 static void Close(vout_display_t *vd);
61 vlc_module_begin ()
62 set_shortname( N_("Flaschen") )
63 set_description( N_("Flaschen-Taschen video output") )
64 set_callback_display( Open, 0 )
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)
72 vlc_module_end ()
75 /*****************************************************************************
76 * Local prototypes
77 *****************************************************************************/
78 struct vout_display_sys_t {
79 int fd;
81 static void Display(vout_display_t *, picture_t *);
82 static int Control(vout_display_t *, int, va_list);
84 /*****************************************************************************
85 * Open: activates flaschen vout display method
86 *****************************************************************************/
87 static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
88 video_format_t *fmtp, vlc_video_context *context)
90 vout_display_sys_t *sys;
91 int fd;
92 const unsigned port = 1337;
94 vd->sys = sys = calloc(1, sizeof(*sys));
95 if (!sys)
96 return VLC_ENOMEM;
97 sys->fd = -1;
99 /* */
100 video_format_t fmt = *fmtp;
101 fmt.i_chroma = VLC_CODEC_RGB24;
102 /* TODO: check if this works on big-endian systems */
103 fmt.i_rmask = 0xff0000;
104 fmt.i_gmask = 0x00ff00;
105 fmt.i_bmask = 0x0000ff;
106 fmt.i_width = var_InheritInteger(vd, "flaschen-width");
107 fmt.i_height = var_InheritInteger(vd, "flaschen-height");
108 fmt.i_visible_width = fmt.i_width;
109 fmt.i_visible_height = fmt.i_height;
111 /* p_vd->info is not modified */
113 char *display = var_InheritString(vd, "flaschen-display");
114 if (display == NULL) {
115 msg_Err(vd, "missing flaschen-display");
116 free(sys);
117 return VLC_EGENERIC;
119 msg_Dbg(vd, "using display at %s (%dx%d)", display, fmt.i_width, fmt.i_height);
121 fd = net_ConnectDgram( vd, display, port, -1, IPPROTO_UDP );
123 if( fd == -1 )
125 msg_Err( vd,
126 "cannot create UDP socket for %s port %u",
127 display, port );
128 free(display);
129 free(sys);
130 return VLC_EGENERIC;
132 free(display);
133 sys->fd = fd;
135 /* Ignore any unexpected incoming packet */
136 setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &(int){ 0 }, sizeof (int));
139 *fmtp = fmt;
141 vd->prepare = NULL;
142 vd->display = Display;
143 vd->control = Control;
144 vd->close = Close;
146 (void) cfg; (void) context;
147 return VLC_SUCCESS;
150 static void Close(vout_display_t *vd)
152 vout_display_sys_t *sys = vd->sys;
154 net_Close(sys->fd);
155 free(sys);
158 static void Display(vout_display_t *vd, picture_t *picture)
160 #ifdef IOV_MAX
161 const long iovmax = IOV_MAX;
162 #else
163 const long iovmax = sysconf(_SC_IOV_MAX);
164 #endif
165 vout_display_sys_t *sys = vd->sys;
166 video_format_t *fmt = &picture->format;
167 int result;
169 char buffer[64];
170 int header_len = snprintf(buffer, sizeof(buffer), "P6\n%d %d\n255\n",
171 fmt->i_width, fmt->i_height);
172 /* TODO: support offset_{x,y,z}? (#FT:...) */
173 /* Note the protocol doesn't include any picture order field. */
174 /* (maybe add as comment?) */
176 int iovcnt = 1 + fmt->i_height;
177 if (unlikely(iovcnt > iovmax))
178 return;
180 struct iovec iov[iovcnt];
181 iov[0].iov_base = buffer;
182 iov[0].iov_len = header_len;
184 uint8_t *src = picture->p->p_pixels;
185 for (int i = 1; i < iovcnt; i++)
187 iov[i].iov_base = src;
188 iov[i].iov_len = fmt->i_width * 3;
189 src += picture->p->i_pitch;
192 struct msghdr hdr = {
193 .msg_name = NULL,
194 .msg_namelen = 0,
195 .msg_iov = iov,
196 .msg_iovlen = iovcnt,
197 .msg_control = NULL,
198 .msg_controllen = 0,
199 .msg_flags = 0 };
201 result = sendmsg(sys->fd, &hdr, 0);
202 if (result < 0)
203 msg_Err(vd, "sendmsg: error %s in vout display flaschen", vlc_strerror_c(errno));
204 else if (result < (int)(header_len + fmt->i_width * fmt->i_height * 3))
205 msg_Err(vd, "sendmsg only sent %d bytes in vout display flaschen", result);
206 /* we might want to drop some frames? */
210 * Control for vout display
212 static int Control(vout_display_t *vd, int query, va_list args)
214 VLC_UNUSED(args);
216 switch (query) {
217 case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
218 case VOUT_DISPLAY_CHANGE_ZOOM:
219 case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
220 case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
221 case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
222 return VLC_SUCCESS;
224 default:
225 msg_Err(vd, "Unsupported query in vout display flaschen");
226 return VLC_EGENERIC;