A comma and a space decide whether you get one session or two
RTSP Server for V4L2 device capture supporting HEVC/H264/JPEG/VP8/VP9
At a glance
- What is it?
- v4l2rtspserver turns a V4L2 capture device into an RTSP stream with four transport modes and optional HLS and DASH output. Its session topology is expressed entirely by how you space and comma your device arguments, and its media core is a library from 2012.
- Who is it for?
- v4l2rtspserver suits a Linux operator who has a raw capture device and needs an RTSP, HLS or DASH endpoint from it without transcoding through a media server stack. It does not suit a camera that already speaks RTSP, or a project that needs maintained codecs beyond the device's own hardware encoders.
- Can I use it commercially?
- Yes. Unlicense is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 18 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 6, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Device arguments are a session description, punctuation included
The most surprising part of this tool is how you ask for streams. A single device gives one RTSP session with RTP video from that V4L2 device. A comma before a name associates an ALSA device with a V4L2 one in a single session carrying both audio and video, so /dev/video0,default is one session and v4l2rtspserver /dev/video0,default binds the audio device to that video device. A space instead separates them into two independent sessions: /dev/video0 ,default is two sessions, the first video and the second audio. Two video devices separated by a space give two sessions with RTP video each. The comma form even accepts the same device twice, /dev/video0,/dev/video0, which is one session with RTP audio and RTP video where the ALSA device is tied to that video device. Nobody discovers this by accident, and the README lists all five forms as examples, which is the correct level of documentation for an interface this positional.
Four RTSP transports and a separate HTTP output mode
The streaming side supports RTP over UDP unicast, RTP over UDP multicast, RTP over TCP, and RTP carried over RTSP on HTTP. Multicast has its own address flag, with -m taking a multicast url defaulting to multicast and -M taking a group and port whose default is a random address on port 20000. The RTSP port defaults to 8554, and a second port for RTSP over HTTP defaults to 0, meaning off. The HTTP server is a separate capability rather than an alternative to RTSP: it is available through the -S option for capture formats that can be muxed into a Transport Stream, and it serves HLS and MPEG-DASH, with -S taking an optional segment duration in seconds. That conditional matters. Without a transport-stream-muxable capture format from the device, the HLS and MPEG-DASH output does not apply, and you are left with the four RTSP transports.
Optional dependencies remove features without failing the build
Four dependencies are marked optional and each one removes a capability rather than breaking the build. liblog4cpp5-dev, under the LGPL, replaces a simple std::cout log with the full logging library, so its absence costs you log routing. libasound2-dev, also LGPL, is what audio support depends on; without it in the build environment there is no audio support at all, and the ALSA options are not even printed by the -h argument, which is a detail that saves you from chasing a flag that does not exist. libssl-dev enables rtsps and srtp, so without it those transports are unavailable. liblivemedia-dev is required rather than optional, and the version requirement is stated as later than live.2012.01.07 with a note that StreamReplicator is needed. That last detail is the one to check on an older distribution, because StreamReplicator arrived in that 2012 line and the media core underneath every session comes from live555.
The media core dates from 2012 and the build downloads it for you
The dependency line reads liblivemedia-dev under the LGPL with a version constraint written as greater than live.2012.01.07 and a parenthetical requirement for StreamReplicator. Every RTP session, every transport mode and the HLS and DASH muxing are built on that library, which means the packetization behavior of the whole project is the behavior of a media library that predates most of the video codecs named in the description. The build instructions accommodate its absence rather than assuming it: cmake . && make, and if live555 is not installed the build downloads it from live555.com and compiles it. If asound is not installed, ALSA is disabled rather than failing. The README goes one step further and says that if it still does not work you will need to read the Makefile, which is an honest statement that the build has escape hatches rather than diagnostics. Optional installation is sudo make install, and packaging is done with cpack .
Authentication is digest-shaped and switched on by a flag
Access control exists and is off until you configure it. Authentication is enabled when at least one user is defined, and users are supplied with -U user:password, repeatable, so -U foo:bar -U admin:admin gives two accounts in plain text. A second form computes an md5 digest from the username, an authentication domain set with -R, and the password:
-R myrealm -U foo:$(echo -n foo:myrealm:bar | md5sum | cut -d- -f1) -U admin:$(echo -n admin:myrealm:admin | md5sum | cut -d- -f1)That construction, md5 of username, domain and password joined by colons, is HTTP digest authentication as it existed before better choices, and it is worth knowing before you put a camera behind a network you do not control. For SRTP and RTSPS there is a separate path, with -x taking an sslkeycert file to enable SRTP and -X enabling RSTPS.
Capture has six modes and the defaults are conservative
The V4L2 side is where most of the tuning happens, and the defaults are chosen for a webcam rather than for a broadcast device. Capture defaults to memory-mapped buffers, with -r switching to the read interface and -w to the write interface. Mode defaults to non-blocking, with -B for blocking. The threading default is a separate reading thread, with -s using the live555 mainloop instead. Format handling has three options: -f uses the current capture format and ignores -W and -H, -fformat sets a named format while using -W and -H, and the default is -G with a w x h x f value of 0x0x25. Geometry defaults are 640 by 480 at 25 frames per second, with -F set to 0 disabling framerate setting entirely. Frame queue length defaults to 10 with -Q. Two integration notes close it out: a Raspberry Pi camera works through the bcm2835-v4l2 kernel module loaded with modprobe -v bcm2835-v4l2, and an uncompressed source can be run through v4l2compress into a v4l2loopback device configured with modprobe v4l2loopback video_nr=1.
Where v4l2rtspserver is the wrong tool
Four cases. The first is a camera that already outputs a network stream. This server takes a raw V4L2 device and republishes it, so a camera with its own RTSP or ONVIF server makes it redundant in the middle of the chain. The second is a device whose hardware cannot produce a transport-stream-muxable format. The HTTP output is conditional on that, so a device that only emits raw frames gets you the four RTSP transports and no HLS or DASH. The third is anyone needing codecs the device cannot encode. The listed capture formats are H264, HEVC, JPEG, VP8 and VP9, which is the set of things hardware does, and there is no software transcoding path described here; if your device emits MJPEG only and your player needs H264, the compression step belongs elsewhere in the chain, and the README points at exactly that case with v4l2compress and v4l2loopback. The fourth is long-term maintenance on a fresh system. The published versions run 0.3.11 in August 2024, 0.3.12 in November 2025 and 0.3.13 in July 2026, so releases are irregular, and the security posture of a server with digest authentication in front of a capture device deserves a look before it faces anything but a trusted network.
Editorial conclusion
v4l2rtspserver suits a Linux operator who has a raw capture device and needs an RTSP, HLS or DASH endpoint from it without transcoding through a media server stack. It does not suit a camera that already speaks RTSP, or a project that needs maintained codecs beyond the device's own hardware encoders. Before adopting, build with cmake . and make, check which optional libraries your distribution provides, and read the device argument examples carefully since punctuation there decides the number of sessions.
Frequently asked questions
How do I stream a V4L2 device over RTSP with v4l2rtspserver?
Build with cmake . && make, then run the binary with the device. A single device gives one RTSP session with RTP video, and the default RTSP port is 8554 with UDP unicast, multicast, TCP and RTSP over HTTP available as transports.
How do I add audio to a v4l2rtspserver stream?
Pass an ALSA device together with the V4L2 device. A comma as in /dev/video0,default gives one session with RTP audio and RTP video, while a space gives two separate sessions. Audio requires libasound2-dev, and without it there is no audio support.
Can v4l2rtspserver produce HLS or MPEG-DASH?
Yes, through the HTTP server enabled with the -S option, but only for capture formats that can be muxed in a Transport Stream. Without such a format you get the four RTSP transports only.
How do I secure v4l2rtspserver?
Define at least one user with -U user:password to enable authentication, optionally combined with the -R domain flag for md5 passwords computed as md5 of the username, the domain and the password. libssl-dev is required for RSTPS with -X and for SRTP with -x.
What does a Raspberry Pi need to use v4l2rtspserver?
The bcm2835-v4l2 kernel module, loaded with sudo modprobe -v bcm2835-v4l2. For an uncompressed source, v4l2compress can write into a v4l2loopback device created with modprobe v4l2loopback video_nr=1.