Skip to content

Instantly share code, notes, and snippets.

@coderofsalvation
Last active June 25, 2026 13:36
Show Gist options
  • Select an option

  • Save coderofsalvation/d38a95a20d30a4303d0a388dd51c487f to your computer and use it in GitHub Desktop.

Select an option

Save coderofsalvation/d38a95a20d30a4303d0a388dd51c487f to your computer and use it in GitHub Desktop.
go2rtc example
# download: https://github.com/AlexxIT/go2rtc/releases
# homepage: https://go2rtc.org
# usage: go2rtc -c go2rtc.yaml
api:
listen: "127.0.0.1:1989"
log:
level: "debug"
streams:
x11:
exec:ffmpeg -f x11grab -i :0.0 -c copy -rtsp_transport tcp -framerate 30 -c:v libx264 -preset ultrafast -tune zerolatency -f rtsp {output}
$ go2rtc -c go2rtc.yaml
http://localhost:1989/api/ (+below)
H264/H265 source
stream.html WebRTC stream / browsers: all / codecs: H264, PCMU, PCMA, OPUS / +H265 in Safari
stream.html MSE stream / browsers: Chrome, Firefox, Safari Mac/iPad / codecs: H264, H265*, AAC, PCMA*, PCMU*, PCM* / +OPUS in Chrome and Firefox
stream.mp4 legacy MP4 stream with AAC audio / browsers: Chrome, Firefox / codecs: H264, H265*, AAC
stream.mp4 modern MP4 stream with common audio / browsers: Chrome, Firefox / codecs: H264, H265*, AAC, FLAC (PCMA, PCMU, PCM)
stream.mp4 MP4 stream with any audio / browsers: Chrome / codecs: H264, H265*, AAC, OPUS, MP3, FLAC (PCMA, PCMU, PCM)
frame.mp4 snapshot in MP4-format / browsers: all / codecs: H264, H265*
stream.m3u8 legacy HLS/TS / browsers: Safari all, Chrome Android / codecs: H264
stream.m3u8 legacy HLS/fMP4 / browsers: Safari all, Chrome Android / codecs: H264, H265*, AAC
stream.m3u8 modern HLS/fMP4 / browsers: Safari all, Chrome Android / codecs: H264, H265*, AAC, FLAC (PCMA, PCMU, PCM)
MJPEG source
stream.html with MJPEG mode / browsers: all / codecs: MJPEG, JPEG
stream.mjpeg MJPEG stream / browsers: all / codecs: MJPEG, JPEG
frame.jpeg snapshot in JPEG-format / browsers: all / codecs: MJPEG, JPEG
<fireboxroom>
<assets>
<assetvideo id="stream" src="http://localhost:1984/api/stream.mp4?src=x11" auto_play="true" loop="true" corsproxy="false"/>
</assets>
<room pos="0 -1 -2" corsproxy="false">
<object id="plane" video_id="stream" scale="1 1 1" rotation="0 180 0"/>
</room>
</fireboxroom>
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="apple-touch-icon" href="https://alexxit.github.io/go2rtc/icons/apple-touch-icon-180x180.png" sizes="180x180">
<link rel="icon" href="https://alexxit.github.io/go2rtc/icons/favicon.ico">
<link rel="manifest" href="https://alexxit.github.io/go2rtc/manifest.json">
<title>go2rtc - Stream</title>
<style>
body {
background: black;
margin: 0;
padding: 0;
display: flex;
font-family: Arial, Helvetica, sans-serif;
}
html, body {
height: 100%;
width: 100%;
}
.flex {
flex-wrap: wrap;
align-content: flex-start;
align-items: flex-start;
}
</style>
</head>
<body>
<script type="module" src="./video-stream.js"></script>
<script type="module">
const params = new URLSearchParams(location.search);
// support multiple streams and multiple modes
const streams = params.getAll('src');
const modes = params.getAll('mode');
if (modes.length === 0) modes.push('');
while (modes.length > streams.length) {
streams.push(streams[0]);
}
while (streams.length > modes.length) {
modes.push(modes[0]);
}
if (streams.length > 1) {
document.body.className = 'flex';
}
const background = params.get('background') !== 'false';
const width = '1 0 ' + (params.get('width') || '320px');
for (let i = 0; i < streams.length; i++) {
/** @type {VideoStream} */
const video = document.createElement('video-stream');
video.background = background;
video.mode = modes[i] || video.mode;
video.style.flex = width;
video.src = new URL('api/ws?src=' + encodeURIComponent(streams[i]), location.href);
document.body.appendChild(video);
}
</script>
</body>
</html>
import {VideoRTC} from './video-rtc.js';
/**
* This is example, how you can extend VideoRTC player for your app.
* Also you can check this example: https://github.com/AlexxIT/WebRTC
*/
class VideoStream extends VideoRTC {
set divMode(value) {
this.querySelector('.mode').innerText = value;
this.querySelector('.status').innerText = '';
}
set divError(value) {
const state = this.querySelector('.mode').innerText;
if (state !== 'loading') return;
this.querySelector('.mode').innerText = 'error';
this.querySelector('.status').innerText = value;
}
/**
* Custom GUI
*/
oninit() {
console.debug('stream.oninit');
super.oninit();
this.innerHTML = `
<style>
video-stream {
position: relative;
}
.info {
position: absolute;
top: 0;
left: 0;
right: 0;
padding: 12px;
color: white;
display: flex;
justify-content: space-between;
pointer-events: none;
}
</style>
<div class="info">
<div class="status"></div>
<div class="mode"></div>
</div>
`;
const info = this.querySelector('.info');
this.insertBefore(this.video, info);
}
onconnect() {
console.debug('stream.onconnect');
const result = super.onconnect();
if (result) this.divMode = 'loading';
return result;
}
ondisconnect() {
console.debug('stream.ondisconnect');
super.ondisconnect();
}
onopen() {
console.debug('stream.onopen');
const result = super.onopen();
this.onmessage['stream'] = msg => {
console.debug('stream.onmessge', msg);
switch (msg.type) {
case 'error':
this.divError = msg.value;
break;
case 'mse':
case 'hls':
case 'mp4':
case 'mjpeg':
this.divMode = msg.type.toUpperCase();
break;
}
};
return result;
}
onclose() {
console.debug('stream.onclose');
return super.onclose();
}
onpcvideo(ev) {
console.debug('stream.onpcvideo');
super.onpcvideo(ev);
if (this.pcState !== WebSocket.CLOSED) {
this.divMode = 'RTC';
}
}
}
customElements.define('video-stream', VideoStream);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment