3 Commits
Author SHA1 Message Date
molluskandClaude Opus 4.7 74b4101d4f vlc-plugin-ffmpeg: extend docs + runtime check
The previous vlc-plugin-dvb diagnosis was incomplete. On a laptop with
only vlc-plugin-dvb installed, VLC reads the MPEG-TS container, sees
the H.264 stream type in the PMT, then errors "Codec h264 ... is not
supported" because libavcodec_plugin.so is also a split package and
also wasn't pulled in by the base `vlc` install.

Installing vlc-plugin-ffmpeg (which pulls ffmpeg4.4 as a compat dep)
on the laptop made VLC play pixelpass cleanly via Intel iHD hardware
decode.

- README: list both plugin packages under requirements; rewrite the
  known-limitations line.
- interactive.rs: extend the launch-time check to also probe for
  libavcodec_plugin.so; combine both into one warning that lists
  every missing piece and the single pacman invocation to fix.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 06:21:32 -04:00
molluskandClaude Opus 4.7 6e4d30bfa9 vlc-plugin-dvb: document and warn at launch
VLC's MPEG-TS demuxer (libts_plugin.so) ships in a separate package on
Arch / CachyOS (vlc-plugin-dvb). Without it, VLC silently falls back
to the PS demuxer and misidentifies our H.264 stream — the symptom is
a green screen. mpv doesn't share this dependency.

- README: list vlc-plugin-dvb under requirements, replace the
  "green screen, not yet diagnosed" gotcha with the diagnosis.
- interactive.rs: when the user picks VLC, check for
  /usr/lib/vlc/plugins/demux/libts_plugin.so and print a warning to
  stderr if it's missing. Soft warning, not a hard error — VLC still
  spawns so the user can confirm the symptom for themselves.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 05:28:19 -04:00
molluskandClaude Opus 4.7 15766834f1 Revert "viewer HTTP: Content-Type application/octet-stream, not video/mp2t"
This reverts commit 0a253bd919.

The Content-Type change was a misdiagnosis. The real cause of VLC's
"no demux modules matched" was a missing `vlc-plugin-dvb` package on
the test machine — Arch/CachyOS ship the MPEG-TS demuxer plugin
(`libts_plugin.so`) in a separate package from `vlc`. Without it, VLC
falls through to the PS demuxer and misidentifies the H.264 stream.
With the package installed, `video/mp2t` opens cleanly.

`video/mp2t` is the correct Content-Type for an MPEG-TS stream and is
what we should be sending. Documentation of the package requirement
and a runtime check follow in a separate commit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 05:26:53 -04:00
3 changed files with 60 additions and 17 deletions
+17 -5
View File
@@ -27,7 +27,6 @@ Not yet working:
- X11 capture (stubbed, returns an error) - X11 capture (stubbed, returns an error)
- Per-app audio routing (`--app <name>` is a flag stub) - Per-app audio routing (`--app <name>` is a flag stub)
- Multi-viewer (single viewer per host by design right now) - Multi-viewer (single viewer per host by design right now)
- VLC client renders the H.264 stream as a green screen — mpv works
- `--repair` (PipeWire orphan cleanup) is a stub - `--repair` (PipeWire orphan cleanup) is a stub
## Quick start ## Quick start
@@ -68,15 +67,26 @@ pixelpass <ticket>
- `gstreamer`, `gst-plugins-base`, `gst-plugins-good`, `gst-plugins-bad`, - `gstreamer`, `gst-plugins-base`, `gst-plugins-good`, `gst-plugins-bad`,
`gst-plugins-ugly`, `gst-libav`, `gst-plugin-va`, `gst-plugin-pipewire` `gst-plugins-ugly`, `gst-libav`, `gst-plugin-va`, `gst-plugin-pipewire`
- A player: `mpv` (recommended) or `vlc` - A player: `mpv` (recommended) or `vlc`
- If you use VLC, two split plugin packages are also needed on Arch-family
distros — the base `vlc` package does not pull them in:
- `vlc-plugin-dvb` — provides the MPEG-TS demuxer (`libts_plugin.so`).
Without it, VLC can't parse the container.
- `vlc-plugin-ffmpeg` — provides the H.264 decoder
(`libavcodec_plugin.so`). Without it, VLC parses the container,
identifies the codec as H.264, then errors with
`Codec h264 ... is not supported`.
mpv ships its own decoder stack and doesn't share either dependency.
- PipeWire (for screencast portal + audio capture) - PipeWire (for screencast portal + audio capture)
On Arch / CachyOS: On Arch / CachyOS / EndeavourOS:
```sh ```sh
sudo pacman -S gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad \ sudo pacman -S gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad \
gst-plugins-ugly gst-libav gst-plugin-va gst-plugin-pipewire \ gst-plugins-ugly gst-libav gst-plugin-va gst-plugin-pipewire \
libva-utils mpv libva-utils mpv
# plus your GPU's VAAPI driver # plus your GPU's VAAPI driver
# plus, if you want to use VLC instead of mpv:
sudo pacman -S vlc vlc-plugin-dvb vlc-plugin-ffmpeg
``` ```
If the viewer is running on battery, set the CPU governor to performance If the viewer is running on battery, set the CPU governor to performance
@@ -146,9 +156,11 @@ relay path otherwise. Both have been verified end-to-end.
## Known limitations and gotchas ## Known limitations and gotchas
- **VLC shows a green screen** against a stream mpv handles correctly. - **VLC needs `vlc-plugin-dvb` and `vlc-plugin-ffmpeg`** on Arch-family
Likely a VLC-specific PCR / PMT / alignment expectation; not yet distros — the base `vlc` package doesn't pull these in, and missing
diagnosed. Use mpv until this is fixed. either one breaks playback (the first kills the demuxer, the second
kills the H.264 decoder). pixelpass warns at player-launch time if
either plugin isn't on disk. mpv doesn't share these dependencies.
- **Audio echo** if the host plays the stream through speakers and - **Audio echo** if the host plays the stream through speakers and
captures system audio — expected, the mic / monitor picks up the captures system audio — expected, the mic / monitor picks up the
playback. Headphones bypass it. playback. Headphones bypass it.
+1 -8
View File
@@ -225,15 +225,8 @@ async fn serve_capture(listener: TcpListener, mut gst_stdout: ChildStdout) {
return; return;
} }
// Content-Type intentionally application/octet-stream, not video/mp2t.
// VLC eagerly maps video/mp2t to demux="ts" and bypasses content
// probing; its ts demuxer's Open then fails on the live HTTP stream
// with "no demux modules matched" and the input never opens. With a
// non-video Content-Type, VLC falls back to byte-probing, which finds
// the TS sync pattern and opens cleanly. mpv probes regardless of
// Content-Type, so it's unaffected.
const RESPONSE: &[u8] = b"HTTP/1.1 200 OK\r\n\ const RESPONSE: &[u8] = b"HTTP/1.1 200 OK\r\n\
Content-Type: application/octet-stream\r\n\ Content-Type: video/mp2t\r\n\
Cache-Control: no-cache, no-store\r\n\ Cache-Control: no-cache, no-store\r\n\
Connection: close\r\n\ Connection: close\r\n\
\r\n"; \r\n";
+42 -4
View File
@@ -68,14 +68,52 @@ impl Player {
url, url,
], ],
), ),
Player::Vlc => crate::common::process::spawn_detached( Player::Vlc => {
"vlc", warn_if_vlc_plugins_missing();
&["--network-caching=200", "--live-caching=200", url], crate::common::process::spawn_detached(
), "vlc",
&["--network-caching=200", "--live-caching=200", url],
)
}
} }
} }
} }
// On Arch-family distros, the base `vlc` package omits two plugins
// pixelpass needs: the MPEG-TS demuxer (`vlc-plugin-dvb`) and the
// libavcodec-based H.264 decoder (`vlc-plugin-ffmpeg`). Missing either
// produces a confusing error chain — warn at launch.
fn warn_if_vlc_plugins_missing() {
const REQUIRED: &[(&str, &str)] = &[
(
"/usr/lib/vlc/plugins/demux/libts_plugin.so",
"vlc-plugin-dvb",
),
(
"/usr/lib/vlc/plugins/codec/libavcodec_plugin.so",
"vlc-plugin-ffmpeg",
),
];
let missing: Vec<&(&str, &str)> = REQUIRED
.iter()
.filter(|(p, _)| !std::path::Path::new(p).exists())
.collect();
if missing.is_empty() {
return;
}
eprintln!();
eprintln!("Warning: VLC is missing plugins pixelpass needs:");
for (path, pkg) in &missing {
eprintln!(" - {path} (install `{pkg}`)");
}
eprintln!("On Arch / CachyOS / EndeavourOS: `sudo pacman -S {}`.", {
let names: Vec<&str> = missing.iter().map(|(_, p)| *p).collect();
names.join(" ")
});
eprintln!("mpv is unaffected.");
eprintln!();
}
pub fn prompt_player() -> Result<Player> { pub fn prompt_player() -> Result<Player> {
let theme = ColorfulTheme::default(); let theme = ColorfulTheme::default();
let choice = Select::with_theme(&theme) let choice = Select::with_theme(&theme)