Skip to content

v2.1.2

Choose a tag to compare

@github-actions github-actions released this 10 Aug 15:20
· 20 commits to main since this release
v2.1.2
89128a1

Emby Watch Party v2.1.2

HEVC sources stop being transcoded for viewers who can already play them.

Until now every stream was requested as H.264, whatever the source was. That is the safe answer when you have no idea what the viewer's browser can decode, and it was the only answer available, because nothing ever asked. So an HEVC file was re-encoded on your Emby server for everybody, including people whose browser would have played the original untouched.

Watch Party now asks. Each viewer's browser reports what it can decode when they join, and the server keeps the source codec for the ones that can handle it. Anyone else still gets H.264, automatically, so nobody is left staring at a black video. Because streams are already built per viewer, two people in the same party can be served different codecs, which is the only thing that works when one is on a Mac and one is on a Windows box without the codec.

Nothing to configure, no .env changes, no migration. Upgrade, restart, done.

When it applies, the difference is not subtle. Measured on an 8K HEVC file, same machine, same browser, the only variable being whether the viewer could decode HEVC:

encoder on your server work per 3s of video
viewer can decode HEVC none, stream copied ~50 ms
viewer cannot libx264 at 1080p ~1750 ms

Whether you actually get this

It depends on the viewer's machine, not just their browser, and that is worth knowing before anyone reports it as a bug:

  • macOS, iOS and Safari decode HEVC natively.
  • Chrome, Edge, Opera and other Chromium browsers on Windows use the GPU directly, but only while hardware acceleration is enabled in the browser's settings. Chromium ships no software HEVC decoder, so turning acceleration off removes HEVC entirely.
  • Firefox on Windows goes through Windows Media Foundation and needs a codec from the Microsoft Store. Windows 11 22H2 and later include it; most Windows 10 installs do not. Try the free HEVC Video Extensions from Device Manufacturer first, which installs on many prebuilt machines; the paid package works everywhere. Third-party codec packs such as K-Lite do not help, because they install DirectShow filters and browsers do not use those.

All of that was confirmed on real machines rather than assumed, including installing and then removing the Store codec and watching the server switch between a stream copy and a transcode with nothing else changed.

Support is detected when you join a party, so if you install a codec or change your hardware-acceleration setting with Watch Party open, reload the page before rejoining.

One practical note that predates this release but matters more now: Auto quality means "do not downscale". That is exactly what you want when the source can be copied, and the worst case when it cannot, because a large source is then re-encoded at full resolution. If a viewer cannot decode HEVC, a capped quality will reach them far sooner than Auto will.

Fixed

  • HEVC and other non-H.264 sources are no longer transcoded unconditionally. VideoCodec=h264 was hardcoded into every stream URL. It is now chosen per viewer from what that viewer's browser reported. Reported by miakkia in #61, including a measurement showing Emby reporting Direct Play once the source codec was preserved.
  • The transcode log line no longer goes stale. "Source is hevc, transcoding to h264" was written independently of the parameter that actually decides, so it kept claiming a transcode that was no longer being requested. Both now come from the same decision, and the message says whether the client could decode the source.

Security

  • nanoid 3.3.16 to 3.3.18 closes GHSA-2v37-7h3g-55p8 (high), where a custom generator can loop indefinitely when asked for a size of zero. Build-time only: it reaches this project through vite and postcss, and it does not appear in the browser bundle, so the realistic exposure is to whoever runs the build rather than to viewers. Included for the same reason postcss was in 2.1.1, which is that there is no reason to ship a known-vulnerable build toolchain. A transitive dependency, so package.json is unchanged and only frontend/package-lock.json moved.

Technical details

TranscodeReasons was not the cause, despite being the obvious suspect. Emby treats it as informational, for logging and telemetry, not as the copy-or-transcode decision, so removing VideoCodecNotSupported alone changes nothing. The forcing was the hardcoded VideoCodec=h264 parameter.

The client probes with MediaSource.isTypeSupported for the hls.js path and canPlayType for native HLS, accepting only probably, since maybe is the browser guessing and a guess is what this exists to avoid. Anything that throws counts as no capability. The server allowlists the reported codecs before they reach an Emby URL, and stores them against the persistent client_id, so they survive a reload the same way the video selector does.

An un-upgraded or silent client sends nothing, which is read as H.264-only. That path was verified to produce output byte-identical to 2.1.1 across h264, hevc and av1 sources at auto, capped and resolution-only qualities, so the upgrade changes nothing at all until a browser actually reports a capability.

Eight tests cover both directions, the two-viewers-differ case, the unchanged H.264 stream-copy fast path, an explicit bitrate cap still forcing a re-encode of a kept codec, and the allowlist rejecting invented codec names.



Installation

Option 1: Docker (Recommended)

Version specific:

docker pull ghcr.io/oratorian/emby-watchparty:2.1.2

Or always latest stable version:

docker pull ghcr.io/oratorian/emby-watchparty:latest

Or use docker-compose with the provided docker-compose.yml.example

Option 2: Manual Installation

  1. Download and extract emby-watchparty-2.1.2.zip
  2. Copy .env.example to .env and configure your Emby server details
  3. Install dependencies: pip install -r requirements.txt
  4. Run: python app.py
  5. Open browser to http://localhost:5000

What's Included

  • Complete application source code
  • Docker support with pre-built images
  • Requirements file for easy dependency installation
  • Example configuration file
  • README with full documentation
  • MIT License

Requirements

  • Python 3.8 or higher (manual install)
  • Docker (container install)
  • Emby server with API key
  • Modern web browser

See README.md for full documentation.