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(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
);
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)
75 /*****************************************************************************
77 *****************************************************************************/
78 struct vout_display_sys_t
{
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
;
92 const unsigned port
= 1337;
94 vd
->sys
= sys
= calloc(1, sizeof(*sys
));
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");
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
);
126 "cannot create UDP socket for %s port %u",
135 /* Ignore any unexpected incoming packet */
136 setsockopt (fd
, SOL_SOCKET
, SO_RCVBUF
, &(int){ 0 }, sizeof (int));
142 vd
->display
= Display
;
143 vd
->control
= Control
;
146 (void) cfg
; (void) context
;
150 static void Close(vout_display_t
*vd
)
152 vout_display_sys_t
*sys
= vd
->sys
;
158 static void Display(vout_display_t
*vd
, picture_t
*picture
)
161 const long iovmax
= IOV_MAX
;
163 const long iovmax
= sysconf(_SC_IOV_MAX
);
165 vout_display_sys_t
*sys
= vd
->sys
;
166 video_format_t
*fmt
= &picture
->format
;
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
))
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
= {
196 .msg_iovlen
= iovcnt
,
201 result
= sendmsg(sys
->fd
, &hdr
, 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
)
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
:
225 msg_Err(vd
, "Unsupported query in vout display flaschen");