Skip to content

Repository files navigation

CrossStream

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Dual video player and scrubber

✨ Features

  • Side-by-side playback: Review your screen recording side-by-side with your teammate's
  • Real-time Synchronization: Synchronized player positions -- review the two recordings in parallel on your local machine, while your teammate is doing the same on theirs
  • Instant Connection, just-in-time transcoding: Your recordings are transcoded and streamed to the other party just-in-time, while you both review -- no need to screen share your video player, or transmit/exchange any video files, or wait for YouTube or Twitch to finish rendering

🚀 Getting Started

Prerequisites

  • Nvidia GPU
  • Python 3.12 or later
  • uv (Python package manager)
  • FFmpeg with FFprobe (must be in system PATH or in the tools/ directory)
  • Modern web browser with WebRTC support (Chrome, Firefox, Edge, or Safari) and h.264 decoder support (e.g. not Chromium)
  • A fellow teammate who you want to review your games with -- must be willing to go through the technical hurdles of setting this up.

Recording Configuration

Nvidia GeForce Experience recording should theoretically work, but hasn't seen much testing recently. AMD and Intel GPUs are currently not supported by the encoder configuration, but should be possible to add in the future.

So for now, OBS is the recommended recording solution.

Here's the recommended configuration:

Under Settings > Output > Recording, set up your desired video quality. We recommend using the Hybrid MP4 (BETA) format, because then you can set chapter marks while recording, which will be picked up by CrossStream.

OBS: Settings > Output > Recording

Under Settings > Output > Audio, define your audio setup.

For now, only the first audio track will be picked up, so you may either set this to your gameplay audio only, if you just want to discuss tactical situations, or you may merge it with all your voice comm tracks, if you also want to discuss communication.

OBS: Settings > Output > Audio

Under Settings > Video, you should set a 16:9 resolution for now.

OBS: Settings > Video

Recording gameplay

Now start a recording on both machines. You don't need to start precisely at the same time, as the videos will get synchronized automatically. You just need to record the same game.

Finish your round and stop the recording on both machines.

Playback and review

  1. Forward the ports:

You'll need to forward two TCP ports from your router to your computer:

By default, these are:

  • Port 6001 for the backend (fetching the configuration from the other machine, downloading its thumbnails and serving the frontend)
  • Port 6002 for the transcoder (fetching the video stream)
  1. Run the app:

Until a full config file solution is implemented, you might want to use a script like this:

:: Set environment variablesSET"MY_PUBLIC_HOSTNAME=me.mydyndns.org"SET"MY_BACKEND_PORT=6001"SET"MY_TRANSCODER_PORT=6002"SET"MY_VIDEO_PATH=D:\Videos\Capture (OBS)":: Run the backend.host module with UV
uv run -m backend.host --host=%MY_PUBLIC_HOSTNAME% --port=%MY_BACKEND_PORT% --transcoder-port=%MY_TRANSCODER_PORT% --media-dir="%MY_VIDEO_PATH%"

Save this in the root CrossStream source directory and run it.

It will automatically pick up the latest video file in the directory. The two videos will automatically be synced based on the time they started recording.

Backend TUI

The backend TUI will launch and display:

  • The log output (current activity) of the backend
  • The log output (current activity) of the transcoder
  • A segment map that reflects transcoder progress

Press Ctrl-Q to quit the backend.

  1. Open the frontend:

Open http://localhost:6001/ in your browser. As soon as your teammate does the same, your two browsers will be connected and you can start reviewing your game. Hover over the scrubber to see a preview and quickly find crucial moments. Use the speaker buttons to activate one of the audio tracks.

📝 Bonus features

Chapter marks

CrossStream will automatically pick up chapter marks from your video file and display them on the scrubber.

One possibility to create these is using a Stream Deck with the OBS Studio > Chapter Marker action.

🙏 Acknowledgements

CrossStream wouldn't be possible without m1k1o/go-transcode, via our own custom fork.

The vast majority of the code has been written by o3 and Claude 4.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - hheimbuerger/crossstream: Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings · GitHub
Skip to content

Repository files navigation

CrossStream

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Dual video player and scrubber

✨ Features

  • Side-by-side playback: Review your screen recording side-by-side with your teammate's
  • Real-time Synchronization: Synchronized player positions -- review the two recordings in parallel on your local machine, while your teammate is doing the same on theirs
  • Instant Connection, just-in-time transcoding: Your recordings are transcoded and streamed to the other party just-in-time, while you both review -- no need to screen share your video player, or transmit/exchange any video files, or wait for YouTube or Twitch to finish rendering

🚀 Getting Started

Prerequisites

  • Nvidia GPU
  • Python 3.12 or later
  • uv (Python package manager)
  • FFmpeg with FFprobe (must be in system PATH or in the tools/ directory)
  • Modern web browser with WebRTC support (Chrome, Firefox, Edge, or Safari) and h.264 decoder support (e.g. not Chromium)
  • A fellow teammate who you want to review your games with -- must be willing to go through the technical hurdles of setting this up.

Recording Configuration

Nvidia GeForce Experience recording should theoretically work, but hasn't seen much testing recently. AMD and Intel GPUs are currently not supported by the encoder configuration, but should be possible to add in the future.

So for now, OBS is the recommended recording solution.

Here's the recommended configuration:

Under Settings > Output > Recording, set up your desired video quality. We recommend using the Hybrid MP4 (BETA) format, because then you can set chapter marks while recording, which will be picked up by CrossStream.

OBS: Settings > Output > Recording

Under Settings > Output > Audio, define your audio setup.

For now, only the first audio track will be picked up, so you may either set this to your gameplay audio only, if you just want to discuss tactical situations, or you may merge it with all your voice comm tracks, if you also want to discuss communication.

OBS: Settings > Output > Audio

Under Settings > Video, you should set a 16:9 resolution for now.

OBS: Settings > Video

Recording gameplay

Now start a recording on both machines. You don't need to start precisely at the same time, as the videos will get synchronized automatically. You just need to record the same game.

Finish your round and stop the recording on both machines.

Playback and review

  1. Forward the ports:

You'll need to forward two TCP ports from your router to your computer:

By default, these are:

  • Port 6001 for the backend (fetching the configuration from the other machine, downloading its thumbnails and serving the frontend)
  • Port 6002 for the transcoder (fetching the video stream)
  1. Run the app:

Until a full config file solution is implemented, you might want to use a script like this:

:: Set environment variablesSET"MY_PUBLIC_HOSTNAME=me.mydyndns.org"SET"MY_BACKEND_PORT=6001"SET"MY_TRANSCODER_PORT=6002"SET"MY_VIDEO_PATH=D:\Videos\Capture (OBS)":: Run the backend.host module with UV
uv run -m backend.host --host=%MY_PUBLIC_HOSTNAME% --port=%MY_BACKEND_PORT% --transcoder-port=%MY_TRANSCODER_PORT% --media-dir="%MY_VIDEO_PATH%"

Save this in the root CrossStream source directory and run it.

It will automatically pick up the latest video file in the directory. The two videos will automatically be synced based on the time they started recording.

Backend TUI

The backend TUI will launch and display:

  • The log output (current activity) of the backend
  • The log output (current activity) of the transcoder
  • A segment map that reflects transcoder progress

Press Ctrl-Q to quit the backend.

  1. Open the frontend:

Open http://localhost:6001/ in your browser. As soon as your teammate does the same, your two browsers will be connected and you can start reviewing your game. Hover over the scrubber to see a preview and quickly find crucial moments. Use the speaker buttons to activate one of the audio tracks.

📝 Bonus features

Chapter marks

CrossStream will automatically pick up chapter marks from your video file and display them on the scrubber.

One possibility to create these is using a Stream Deck with the OBS Studio > Chapter Marker action.

🙏 Acknowledgements

CrossStream wouldn't be possible without m1k1o/go-transcode, via our own custom fork.

The vast majority of the code has been written by o3 and Claude 4.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - hheimbuerger/crossstream: Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings · GitHub
Skip to content

Repository files navigation

CrossStream

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Dual video player and scrubber

✨ Features

  • Side-by-side playback: Review your screen recording side-by-side with your teammate's
  • Real-time Synchronization: Synchronized player positions -- review the two recordings in parallel on your local machine, while your teammate is doing the same on theirs
  • Instant Connection, just-in-time transcoding: Your recordings are transcoded and streamed to the other party just-in-time, while you both review -- no need to screen share your video player, or transmit/exchange any video files, or wait for YouTube or Twitch to finish rendering

🚀 Getting Started

Prerequisites

  • Nvidia GPU
  • Python 3.12 or later
  • uv (Python package manager)
  • FFmpeg with FFprobe (must be in system PATH or in the tools/ directory)
  • Modern web browser with WebRTC support (Chrome, Firefox, Edge, or Safari) and h.264 decoder support (e.g. not Chromium)
  • A fellow teammate who you want to review your games with -- must be willing to go through the technical hurdles of setting this up.

Recording Configuration

Nvidia GeForce Experience recording should theoretically work, but hasn't seen much testing recently. AMD and Intel GPUs are currently not supported by the encoder configuration, but should be possible to add in the future.

So for now, OBS is the recommended recording solution.

Here's the recommended configuration:

Under Settings > Output > Recording, set up your desired video quality. We recommend using the Hybrid MP4 (BETA) format, because then you can set chapter marks while recording, which will be picked up by CrossStream.

OBS: Settings > Output > Recording

Under Settings > Output > Audio, define your audio setup.

For now, only the first audio track will be picked up, so you may either set this to your gameplay audio only, if you just want to discuss tactical situations, or you may merge it with all your voice comm tracks, if you also want to discuss communication.

OBS: Settings > Output > Audio

Under Settings > Video, you should set a 16:9 resolution for now.

OBS: Settings > Video

Recording gameplay

Now start a recording on both machines. You don't need to start precisely at the same time, as the videos will get synchronized automatically. You just need to record the same game.

Finish your round and stop the recording on both machines.

Playback and review

  1. Forward the ports:

You'll need to forward two TCP ports from your router to your computer:

By default, these are:

  • Port 6001 for the backend (fetching the configuration from the other machine, downloading its thumbnails and serving the frontend)
  • Port 6002 for the transcoder (fetching the video stream)
  1. Run the app:

Until a full config file solution is implemented, you might want to use a script like this:

:: Set environment variablesSET"MY_PUBLIC_HOSTNAME=me.mydyndns.org"SET"MY_BACKEND_PORT=6001"SET"MY_TRANSCODER_PORT=6002"SET"MY_VIDEO_PATH=D:\Videos\Capture (OBS)":: Run the backend.host module with UV
uv run -m backend.host --host=%MY_PUBLIC_HOSTNAME% --port=%MY_BACKEND_PORT% --transcoder-port=%MY_TRANSCODER_PORT% --media-dir="%MY_VIDEO_PATH%"

Save this in the root CrossStream source directory and run it.

It will automatically pick up the latest video file in the directory. The two videos will automatically be synced based on the time they started recording.

Backend TUI

The backend TUI will launch and display:

  • The log output (current activity) of the backend
  • The log output (current activity) of the transcoder
  • A segment map that reflects transcoder progress

Press Ctrl-Q to quit the backend.

  1. Open the frontend:

Open http://localhost:6001/ in your browser. As soon as your teammate does the same, your two browsers will be connected and you can start reviewing your game. Hover over the scrubber to see a preview and quickly find crucial moments. Use the speaker buttons to activate one of the audio tracks.

📝 Bonus features

Chapter marks

CrossStream will automatically pick up chapter marks from your video file and display them on the scrubber.

One possibility to create these is using a Stream Deck with the OBS Studio > Chapter Marker action.

🙏 Acknowledgements

CrossStream wouldn't be possible without m1k1o/go-transcode, via our own custom fork.

The vast majority of the code has been written by o3 and Claude 4.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - hheimbuerger/crossstream: Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings · GitHub
Skip to content

Repository files navigation

CrossStream

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Dual video player and scrubber

✨ Features

  • Side-by-side playback: Review your screen recording side-by-side with your teammate's
  • Real-time Synchronization: Synchronized player positions -- review the two recordings in parallel on your local machine, while your teammate is doing the same on theirs
  • Instant Connection, just-in-time transcoding: Your recordings are transcoded and streamed to the other party just-in-time, while you both review -- no need to screen share your video player, or transmit/exchange any video files, or wait for YouTube or Twitch to finish rendering

🚀 Getting Started

Prerequisites

  • Nvidia GPU
  • Python 3.12 or later
  • uv (Python package manager)
  • FFmpeg with FFprobe (must be in system PATH or in the tools/ directory)
  • Modern web browser with WebRTC support (Chrome, Firefox, Edge, or Safari) and h.264 decoder support (e.g. not Chromium)
  • A fellow teammate who you want to review your games with -- must be willing to go through the technical hurdles of setting this up.

Recording Configuration

Nvidia GeForce Experience recording should theoretically work, but hasn't seen much testing recently. AMD and Intel GPUs are currently not supported by the encoder configuration, but should be possible to add in the future.

So for now, OBS is the recommended recording solution.

Here's the recommended configuration:

Under Settings > Output > Recording, set up your desired video quality. We recommend using the Hybrid MP4 (BETA) format, because then you can set chapter marks while recording, which will be picked up by CrossStream.

OBS: Settings > Output > Recording

Under Settings > Output > Audio, define your audio setup.

For now, only the first audio track will be picked up, so you may either set this to your gameplay audio only, if you just want to discuss tactical situations, or you may merge it with all your voice comm tracks, if you also want to discuss communication.

OBS: Settings > Output > Audio

Under Settings > Video, you should set a 16:9 resolution for now.

OBS: Settings > Video

Recording gameplay

Now start a recording on both machines. You don't need to start precisely at the same time, as the videos will get synchronized automatically. You just need to record the same game.

Finish your round and stop the recording on both machines.

Playback and review

  1. Forward the ports:

You'll need to forward two TCP ports from your router to your computer:

By default, these are:

  • Port 6001 for the backend (fetching the configuration from the other machine, downloading its thumbnails and serving the frontend)
  • Port 6002 for the transcoder (fetching the video stream)
  1. Run the app:

Until a full config file solution is implemented, you might want to use a script like this:

:: Set environment variablesSET"MY_PUBLIC_HOSTNAME=me.mydyndns.org"SET"MY_BACKEND_PORT=6001"SET"MY_TRANSCODER_PORT=6002"SET"MY_VIDEO_PATH=D:\Videos\Capture (OBS)":: Run the backend.host module with UV
uv run -m backend.host --host=%MY_PUBLIC_HOSTNAME% --port=%MY_BACKEND_PORT% --transcoder-port=%MY_TRANSCODER_PORT% --media-dir="%MY_VIDEO_PATH%"

Save this in the root CrossStream source directory and run it.

It will automatically pick up the latest video file in the directory. The two videos will automatically be synced based on the time they started recording.

Backend TUI

The backend TUI will launch and display:

  • The log output (current activity) of the backend
  • The log output (current activity) of the transcoder
  • A segment map that reflects transcoder progress

Press Ctrl-Q to quit the backend.

  1. Open the frontend:

Open http://localhost:6001/ in your browser. As soon as your teammate does the same, your two browsers will be connected and you can start reviewing your game. Hover over the scrubber to see a preview and quickly find crucial moments. Use the speaker buttons to activate one of the audio tracks.

📝 Bonus features

Chapter marks

CrossStream will automatically pick up chapter marks from your video file and display them on the scrubber.

One possibility to create these is using a Stream Deck with the OBS Studio > Chapter Marker action.

🙏 Acknowledgements

CrossStream wouldn't be possible without m1k1o/go-transcode, via our own custom fork.

The vast majority of the code has been written by o3 and Claude 4.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - hheimbuerger/crossstream: Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings · GitHub
Skip to content

Repository files navigation

CrossStream

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Dual video player and scrubber

✨ Features

  • Side-by-side playback: Review your screen recording side-by-side with your teammate's
  • Real-time Synchronization: Synchronized player positions -- review the two recordings in parallel on your local machine, while your teammate is doing the same on theirs
  • Instant Connection, just-in-time transcoding: Your recordings are transcoded and streamed to the other party just-in-time, while you both review -- no need to screen share your video player, or transmit/exchange any video files, or wait for YouTube or Twitch to finish rendering

🚀 Getting Started

Prerequisites

  • Nvidia GPU
  • Python 3.12 or later
  • uv (Python package manager)
  • FFmpeg with FFprobe (must be in system PATH or in the tools/ directory)
  • Modern web browser with WebRTC support (Chrome, Firefox, Edge, or Safari) and h.264 decoder support (e.g. not Chromium)
  • A fellow teammate who you want to review your games with -- must be willing to go through the technical hurdles of setting this up.

Recording Configuration

Nvidia GeForce Experience recording should theoretically work, but hasn't seen much testing recently. AMD and Intel GPUs are currently not supported by the encoder configuration, but should be possible to add in the future.

So for now, OBS is the recommended recording solution.

Here's the recommended configuration:

Under Settings > Output > Recording, set up your desired video quality. We recommend using the Hybrid MP4 (BETA) format, because then you can set chapter marks while recording, which will be picked up by CrossStream.

OBS: Settings > Output > Recording

Under Settings > Output > Audio, define your audio setup.

For now, only the first audio track will be picked up, so you may either set this to your gameplay audio only, if you just want to discuss tactical situations, or you may merge it with all your voice comm tracks, if you also want to discuss communication.

OBS: Settings > Output > Audio

Under Settings > Video, you should set a 16:9 resolution for now.

OBS: Settings > Video

Recording gameplay

Now start a recording on both machines. You don't need to start precisely at the same time, as the videos will get synchronized automatically. You just need to record the same game.

Finish your round and stop the recording on both machines.

Playback and review

  1. Forward the ports:

You'll need to forward two TCP ports from your router to your computer:

By default, these are:

  • Port 6001 for the backend (fetching the configuration from the other machine, downloading its thumbnails and serving the frontend)
  • Port 6002 for the transcoder (fetching the video stream)
  1. Run the app:

Until a full config file solution is implemented, you might want to use a script like this:

:: Set environment variablesSET"MY_PUBLIC_HOSTNAME=me.mydyndns.org"SET"MY_BACKEND_PORT=6001"SET"MY_TRANSCODER_PORT=6002"SET"MY_VIDEO_PATH=D:\Videos\Capture (OBS)":: Run the backend.host module with UV
uv run -m backend.host --host=%MY_PUBLIC_HOSTNAME% --port=%MY_BACKEND_PORT% --transcoder-port=%MY_TRANSCODER_PORT% --media-dir="%MY_VIDEO_PATH%"

Save this in the root CrossStream source directory and run it.

It will automatically pick up the latest video file in the directory. The two videos will automatically be synced based on the time they started recording.

Backend TUI

The backend TUI will launch and display:

  • The log output (current activity) of the backend
  • The log output (current activity) of the transcoder
  • A segment map that reflects transcoder progress

Press Ctrl-Q to quit the backend.

  1. Open the frontend:

Open http://localhost:6001/ in your browser. As soon as your teammate does the same, your two browsers will be connected and you can start reviewing your game. Hover over the scrubber to see a preview and quickly find crucial moments. Use the speaker buttons to activate one of the audio tracks.

📝 Bonus features

Chapter marks

CrossStream will automatically pick up chapter marks from your video file and display them on the scrubber.

One possibility to create these is using a Stream Deck with the OBS Studio > Chapter Marker action.

🙏 Acknowledgements

CrossStream wouldn't be possible without m1k1o/go-transcode, via our own custom fork.

The vast majority of the code has been written by o3 and Claude 4.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - hheimbuerger/crossstream: Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings · GitHub
Skip to content

Repository files navigation

CrossStream

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Dual video player and scrubber

✨ Features

  • Side-by-side playback: Review your screen recording side-by-side with your teammate's
  • Real-time Synchronization: Synchronized player positions -- review the two recordings in parallel on your local machine, while your teammate is doing the same on theirs
  • Instant Connection, just-in-time transcoding: Your recordings are transcoded and streamed to the other party just-in-time, while you both review -- no need to screen share your video player, or transmit/exchange any video files, or wait for YouTube or Twitch to finish rendering

🚀 Getting Started

Prerequisites

  • Nvidia GPU
  • Python 3.12 or later
  • uv (Python package manager)
  • FFmpeg with FFprobe (must be in system PATH or in the tools/ directory)
  • Modern web browser with WebRTC support (Chrome, Firefox, Edge, or Safari) and h.264 decoder support (e.g. not Chromium)
  • A fellow teammate who you want to review your games with -- must be willing to go through the technical hurdles of setting this up.

Recording Configuration

Nvidia GeForce Experience recording should theoretically work, but hasn't seen much testing recently. AMD and Intel GPUs are currently not supported by the encoder configuration, but should be possible to add in the future.

So for now, OBS is the recommended recording solution.

Here's the recommended configuration:

Under Settings > Output > Recording, set up your desired video quality. We recommend using the Hybrid MP4 (BETA) format, because then you can set chapter marks while recording, which will be picked up by CrossStream.

OBS: Settings > Output > Recording

Under Settings > Output > Audio, define your audio setup.

For now, only the first audio track will be picked up, so you may either set this to your gameplay audio only, if you just want to discuss tactical situations, or you may merge it with all your voice comm tracks, if you also want to discuss communication.

OBS: Settings > Output > Audio

Under Settings > Video, you should set a 16:9 resolution for now.

OBS: Settings > Video

Recording gameplay

Now start a recording on both machines. You don't need to start precisely at the same time, as the videos will get synchronized automatically. You just need to record the same game.

Finish your round and stop the recording on both machines.

Playback and review

  1. Forward the ports:

You'll need to forward two TCP ports from your router to your computer:

By default, these are:

  • Port 6001 for the backend (fetching the configuration from the other machine, downloading its thumbnails and serving the frontend)
  • Port 6002 for the transcoder (fetching the video stream)
  1. Run the app:

Until a full config file solution is implemented, you might want to use a script like this:

:: Set environment variablesSET"MY_PUBLIC_HOSTNAME=me.mydyndns.org"SET"MY_BACKEND_PORT=6001"SET"MY_TRANSCODER_PORT=6002"SET"MY_VIDEO_PATH=D:\Videos\Capture (OBS)":: Run the backend.host module with UV
uv run -m backend.host --host=%MY_PUBLIC_HOSTNAME% --port=%MY_BACKEND_PORT% --transcoder-port=%MY_TRANSCODER_PORT% --media-dir="%MY_VIDEO_PATH%"

Save this in the root CrossStream source directory and run it.

It will automatically pick up the latest video file in the directory. The two videos will automatically be synced based on the time they started recording.

Backend TUI

The backend TUI will launch and display:

  • The log output (current activity) of the backend
  • The log output (current activity) of the transcoder
  • A segment map that reflects transcoder progress

Press Ctrl-Q to quit the backend.

  1. Open the frontend:

Open http://localhost:6001/ in your browser. As soon as your teammate does the same, your two browsers will be connected and you can start reviewing your game. Hover over the scrubber to see a preview and quickly find crucial moments. Use the speaker buttons to activate one of the audio tracks.

📝 Bonus features

Chapter marks

CrossStream will automatically pick up chapter marks from your video file and display them on the scrubber.

One possibility to create these is using a Stream Deck with the OBS Studio > Chapter Marker action.

🙏 Acknowledgements

CrossStream wouldn't be possible without m1k1o/go-transcode, via our own custom fork.

The vast majority of the code has been written by o3 and Claude 4.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - hheimbuerger/crossstream: Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings · GitHub
Skip to content

Repository files navigation

CrossStream

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Dual video player and scrubber

✨ Features

  • Side-by-side playback: Review your screen recording side-by-side with your teammate's
  • Real-time Synchronization: Synchronized player positions -- review the two recordings in parallel on your local machine, while your teammate is doing the same on theirs
  • Instant Connection, just-in-time transcoding: Your recordings are transcoded and streamed to the other party just-in-time, while you both review -- no need to screen share your video player, or transmit/exchange any video files, or wait for YouTube or Twitch to finish rendering

🚀 Getting Started

Prerequisites

  • Nvidia GPU
  • Python 3.12 or later
  • uv (Python package manager)
  • FFmpeg with FFprobe (must be in system PATH or in the tools/ directory)
  • Modern web browser with WebRTC support (Chrome, Firefox, Edge, or Safari) and h.264 decoder support (e.g. not Chromium)
  • A fellow teammate who you want to review your games with -- must be willing to go through the technical hurdles of setting this up.

Recording Configuration

Nvidia GeForce Experience recording should theoretically work, but hasn't seen much testing recently. AMD and Intel GPUs are currently not supported by the encoder configuration, but should be possible to add in the future.

So for now, OBS is the recommended recording solution.

Here's the recommended configuration:

Under Settings > Output > Recording, set up your desired video quality. We recommend using the Hybrid MP4 (BETA) format, because then you can set chapter marks while recording, which will be picked up by CrossStream.

OBS: Settings > Output > Recording

Under Settings > Output > Audio, define your audio setup.

For now, only the first audio track will be picked up, so you may either set this to your gameplay audio only, if you just want to discuss tactical situations, or you may merge it with all your voice comm tracks, if you also want to discuss communication.

OBS: Settings > Output > Audio

Under Settings > Video, you should set a 16:9 resolution for now.

OBS: Settings > Video

Recording gameplay

Now start a recording on both machines. You don't need to start precisely at the same time, as the videos will get synchronized automatically. You just need to record the same game.

Finish your round and stop the recording on both machines.

Playback and review

  1. Forward the ports:

You'll need to forward two TCP ports from your router to your computer:

By default, these are:

  • Port 6001 for the backend (fetching the configuration from the other machine, downloading its thumbnails and serving the frontend)
  • Port 6002 for the transcoder (fetching the video stream)
  1. Run the app:

Until a full config file solution is implemented, you might want to use a script like this:

:: Set environment variablesSET"MY_PUBLIC_HOSTNAME=me.mydyndns.org"SET"MY_BACKEND_PORT=6001"SET"MY_TRANSCODER_PORT=6002"SET"MY_VIDEO_PATH=D:\Videos\Capture (OBS)":: Run the backend.host module with UV
uv run -m backend.host --host=%MY_PUBLIC_HOSTNAME% --port=%MY_BACKEND_PORT% --transcoder-port=%MY_TRANSCODER_PORT% --media-dir="%MY_VIDEO_PATH%"

Save this in the root CrossStream source directory and run it.

It will automatically pick up the latest video file in the directory. The two videos will automatically be synced based on the time they started recording.

Backend TUI

The backend TUI will launch and display:

  • The log output (current activity) of the backend
  • The log output (current activity) of the transcoder
  • A segment map that reflects transcoder progress

Press Ctrl-Q to quit the backend.

  1. Open the frontend:

Open http://localhost:6001/ in your browser. As soon as your teammate does the same, your two browsers will be connected and you can start reviewing your game. Hover over the scrubber to see a preview and quickly find crucial moments. Use the speaker buttons to activate one of the audio tracks.

📝 Bonus features

Chapter marks

CrossStream will automatically pick up chapter marks from your video file and display them on the scrubber.

One possibility to create these is using a Stream Deck with the OBS Studio > Chapter Marker action.

🙏 Acknowledgements

CrossStream wouldn't be possible without m1k1o/go-transcode, via our own custom fork.

The vast majority of the code has been written by o3 and Claude 4.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - hheimbuerger/crossstream: Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings · GitHub
Skip to content

Repository files navigation

CrossStream

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Dual video player and scrubber

✨ Features

  • Side-by-side playback: Review your screen recording side-by-side with your teammate's
  • Real-time Synchronization: Synchronized player positions -- review the two recordings in parallel on your local machine, while your teammate is doing the same on theirs
  • Instant Connection, just-in-time transcoding: Your recordings are transcoded and streamed to the other party just-in-time, while you both review -- no need to screen share your video player, or transmit/exchange any video files, or wait for YouTube or Twitch to finish rendering

🚀 Getting Started

Prerequisites

  • Nvidia GPU
  • Python 3.12 or later
  • uv (Python package manager)
  • FFmpeg with FFprobe (must be in system PATH or in the tools/ directory)
  • Modern web browser with WebRTC support (Chrome, Firefox, Edge, or Safari) and h.264 decoder support (e.g. not Chromium)
  • A fellow teammate who you want to review your games with -- must be willing to go through the technical hurdles of setting this up.

Recording Configuration

Nvidia GeForce Experience recording should theoretically work, but hasn't seen much testing recently. AMD and Intel GPUs are currently not supported by the encoder configuration, but should be possible to add in the future.

So for now, OBS is the recommended recording solution.

Here's the recommended configuration:

Under Settings > Output > Recording, set up your desired video quality. We recommend using the Hybrid MP4 (BETA) format, because then you can set chapter marks while recording, which will be picked up by CrossStream.

OBS: Settings > Output > Recording

Under Settings > Output > Audio, define your audio setup.

For now, only the first audio track will be picked up, so you may either set this to your gameplay audio only, if you just want to discuss tactical situations, or you may merge it with all your voice comm tracks, if you also want to discuss communication.

OBS: Settings > Output > Audio

Under Settings > Video, you should set a 16:9 resolution for now.

OBS: Settings > Video

Recording gameplay

Now start a recording on both machines. You don't need to start precisely at the same time, as the videos will get synchronized automatically. You just need to record the same game.

Finish your round and stop the recording on both machines.

Playback and review

  1. Forward the ports:

You'll need to forward two TCP ports from your router to your computer:

By default, these are:

  • Port 6001 for the backend (fetching the configuration from the other machine, downloading its thumbnails and serving the frontend)
  • Port 6002 for the transcoder (fetching the video stream)
  1. Run the app:

Until a full config file solution is implemented, you might want to use a script like this:

:: Set environment variablesSET"MY_PUBLIC_HOSTNAME=me.mydyndns.org"SET"MY_BACKEND_PORT=6001"SET"MY_TRANSCODER_PORT=6002"SET"MY_VIDEO_PATH=D:\Videos\Capture (OBS)":: Run the backend.host module with UV
uv run -m backend.host --host=%MY_PUBLIC_HOSTNAME% --port=%MY_BACKEND_PORT% --transcoder-port=%MY_TRANSCODER_PORT% --media-dir="%MY_VIDEO_PATH%"

Save this in the root CrossStream source directory and run it.

It will automatically pick up the latest video file in the directory. The two videos will automatically be synced based on the time they started recording.

Backend TUI

The backend TUI will launch and display:

  • The log output (current activity) of the backend
  • The log output (current activity) of the transcoder
  • A segment map that reflects transcoder progress

Press Ctrl-Q to quit the backend.

  1. Open the frontend:

Open http://localhost:6001/ in your browser. As soon as your teammate does the same, your two browsers will be connected and you can start reviewing your game. Hover over the scrubber to see a preview and quickly find crucial moments. Use the speaker buttons to activate one of the audio tracks.

📝 Bonus features

Chapter marks

CrossStream will automatically pick up chapter marks from your video file and display them on the scrubber.

One possibility to create these is using a Stream Deck with the OBS Studio > Chapter Marker action.

🙏 Acknowledgements

CrossStream wouldn't be possible without m1k1o/go-transcode, via our own custom fork.

The vast majority of the code has been written by o3 and Claude 4.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Synchronized side-by-side video player for instant collaborative review of concurrent screen recordings

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages