Skip to content

COMPARISON

Shannon Atkinson edited this page Aug 27, 2026 · 1 revision

Generated from docs/COMPARISON.md. Edit that file and re-run node scripts/publish-wiki.mjs --push. An edit made here is a fork of the documentation that nothing reconciles, and the next run of this script will overwrite it without asking.

polyemesis vs Restreamer, restream.io, obs-multi-rtmp, Aitum and MistServer

An honest comparison, including the parts where polyemesis loses.

Sourced from a survey of Restreamer's issue trackers (263 open, 548 closed) and restream.io's published plan comparison, done 2026-07-27 — with the polyemesis column verified against the code rather than assumed.

The polyemesis column was re-verified 2026-07-30, and three rows had gone stale in the product's favour: overlays and MQTT had shipped while still listed as missing, and LL-HLS had been deliberately declined rather than merely absent. A comparison page drifts in whichever direction the project moves, so the column is worth re-checking whenever this page is cited.

Re-verified again 2026-08-07 while surveying Castr, and the same drift had happened twice more: both playlist rows still said "Partial — no sequencing" long after internal/playlistmedia, -stream_loop -1 and the scheduler's playlist.start / playlist.stop actions shipped. Note the direction — every stale row so far has understated the product, because the page is written when a gap is found and nobody returns to it when the gap closes.

2026-08-09: three tools were missing from the page entirely. obs-multi-rtmp, Aitum Multistream and MistServer are what a prospect is usually already running when they find this project, and a comparison that omits the incumbent is not credible. They are added below. Each claim about them was read in their own source rather than taken from their marketing, and every external fact on this page now carries the date it was checked — including the ones that were already here. The drift warning above applies to those rows too: they are one person's reading of somebody else's repository on one day.


The short version

If you do not need different audio per destination, you already have a tool. Multistreaming from the stream PC: obs-multi-rtmp is free, mature and enough. Want a server instead: Restreamer is more mature and far more widely deployed than this. Want no server at all: restream.io. Want an industrial-strength media server with real track selection: MistServer.

polyemesis exists for one case none of them serve: this platform gets the clean mix, that one gets the full mix, from one upload and one video encode. If that is not your problem, the rest of this page is academic.

They select a track. polyemesis mixes.

This is the whole difference, and it is narrower and more checkable than "better audio support", so it is worth stating as something you can go and read rather than as a claim you have to take on trust.

Every tool here can decide which audio track leaves for a destination. None of them can decide what is in it.

  • obs-multi-rtmpsrc/output-config.h, checked 2026-08-09:

    struct AudioTrackConfig {
        int mixer_track;
        int output_track;
    };

    A pair of integers: this OBS mixer track goes in that output track slot. No gain, no sum, no matrix. It is an assignment.

  • Aitum Multistreammultistream.cpp, checked 2026-08-09, builds each destination's encoder with obs_audio_encoder_create(..., obs_data_get_int(settings, "audio_track"), ...). One integer per destination: the mixer index that destination takes.

  • MistServerUtil::wouldSelect() in lib/stream.cpp, checked 2026-08-09, reads audio= and video= off a push target's query string and resolves them through Util::findTracks, which also accepts all and *. So a MistServer push target genuinely can carry different tracks from the one before it, and anyone who tells you a media server cannot select tracks has not read this file. It selects well. Its routing server does not mix: there is no amix, no downmix, no loudnorm and no ebur128 anywhere under src/ or lib/. The audio path in src/process/process_av.cpp is swr_alloc_set_opts, a resampler — one track in, one track out.

    Scoped deliberately, because the unscoped version is wrong. An external Stream Process (MistProcAV, an FFmpeg pipeline) can decode, filter and inject a track back into the buffer, so amix and loudnorm are reachable — just not in the server that does the routing (competitor-facts §6, checked 2026-08-15). Saying "MistServer does not mix" is the same error as saying the OBS plugins cannot send different audio per destination: true of one layer, false of the product.

  • OBS itself — the Twitch VOD track is obs_audio_encoder_create(..., vodTrack, ...), and VodTrackMixerIdx() returns nothing unless ServiceSupportsVodTrack(service) (obsproject/obs-studio frontend/utility/AdvancedOutput.cpp, checked 2026-08-09). One extra selected track, for a service that has opted into it.

polyemesis sums. A destination's mix is the set of ingest tracks you chose, summed, with a gain per input-channel-to-output-channel cell, and a loudness target measured after the routing — see AUDIO-ROUTING.md. That is a different operation from selection, which is why "add per-destination audio to obs-multi-rtmp" is not a small patch to obs-multi-rtmp.

And here is what mixing costs. Selecting a track is a copy; mixing means decoding the audio and encoding it again, once per destination. polyemesis does that on every destination. The video is stream-copied so the bill stays small, but it is not zero, and a selector's is.

What polyemesis has that none of them have

Capability Restreamer restream.io obs-multi-rtmp Aitum MistServer
Per-destination audio mix from one multitrack ingest No No No No No
Channel-level mix matrix with per-cell gain No No No No No
Per-destination loudness TARGET you set — I, LRA and TP, measured after routing Filter only4 No No No No
Multitrack archive — every ingest track preserved, stream-copied No No Via OBS Via OBS Yes
Per-track stems as 24-bit WAV or FLAC, segment-aligned to the master No No No No No
Track annotations — what each incoming track actually is No No n/a n/a Unverified
Typed SRT rejections — the publisher is told why it was refused No n/a n/a n/a Unverified
A second audio mix to the same destination, from one ingest No n/a n/a n/a Twitch Enhanced Broadcasting, and it needs a supported GPU; competitors unverified

EXPERIMENTAL, on the last row only — no broadcast has been published through a key Twitch minted. The negotiation is not the gap: polyemesis's own tests reach ingest.twitch.tv on every run, and Twitch accepts a supported-GPU inventory, grants the VOD audio track and mints a key. What has never been observed is everything after that. On a non-Twitch destination the two-mix egress is a different mechanism and is not covered by this caveat. Nothing is gated: a negotiation that does not succeed falls back to the ordinary Twitch ingest. See AUDIO-ROUTING.md § Two mixes to one destination.

Two cells say Unverified rather than "No" on purpose. MistServer's own recording row is a loss and is marked as one: a recording target with ?audio=all keeps every track (Util::findTracks, lib/stream.cpp, checked 2026-08-09), which is the same outcome as our multitrack archive by a different route. The two "Unverified" cells are things nobody has gone and read, and this page does not guess.

The multitrack ask is not hypothetical. "Multiple audio tracks for Twitch" is an open request on Restreamer's tracker with 8 reactions (surveyed 2026-07-27) — users asking Restreamer for the thing polyemesis was built to be.

What the OBS plugins have that polyemesis does not

obs-multi-rtmp (GPL-2.0, last pushed 2026-08-01) and Aitum Multistream (GPL-2.0, last pushed 2026-05-19), both checked 2026-08-09. Star counts used to appear here and are gone: a number nobody re-checks is the kind of claim this document cannot afford, and it is not in the facts file. They are the honest incumbent: free, installed in two minutes, and already on the machine.

What they have polyemesis
No server at all. A plugin in OBS, no host to provision, no port to open You run a server, or there is nothing to run
Nothing new to learn. The destinations sit in OBS beside the ones already there A second UI, a second set of concepts
No extra hop. OBS talks to the platform directly, so nothing in the middle can fail The server is one more thing between you and air
Per-target video encoder settings, decided in OBS Shared renditions, decided on the server

What they cost you is upload. Each target in MultiOutputConfig is another OBS output with its own service parameters and its own optional encoder config (src/output-config.h, checked 2026-08-09), so N destinations is N uploads off one connection, and N video encodes on the machine that is also running the show. polyemesis takes one upload and stream-copies the video to all of them. That trade is the entire reason to put a server in the path, and if your upload is comfortable it is not a reason at all.

What Restreamer has that polyemesis does not

Ranked by how often it was asked for, which is the honest ordering. Reaction counts surveyed 2026-07-27.

Gap Evidence Status here
Overlays — text, logo, watermark, channel name Asked 5 separate times (6+5+4+2+1 reactions), every one closed unimplemented Have. Image watermarks and text overlays on renditions, where re-encoding is already the contract. Nine anchors, sizes as a percentage of the frame so one logo is correct on landscape and vertical tiers alike; two weights of Inter ship embedded because drawtext needs a font path
WebRTC / WHIP output 6 reactions, closed unimplemented Missing. Sizeable subsystem; the real use case is sub-second self-monitoring
Decklink / SDI capture, in and out 4 + 2 reactions Missing. Needs an FFmpeg built with decklink, so a third image variant
Deinterlacing 1 reaction Have. bwdif with off / only-interlaced / every-frame, placed first in the filter chain because scaling interlaced content bakes the combing in
Playlist / scheduled file broadcast Five issues circling one capability Have, with one caveat. An ordered list of uploads played through FFmpeg's concat demuxer under -stream_loop -1, and playlist.start / playlist.stop are scheduler actions. Every upload is normalised once on import to a single fixed profile (playlistmedia), because concat refuses a set whose codecs, timebase, resolution or channel layout disagree — and plays a drifting, tearing one if it does not refuse. The caveat: the playlist lives under failover.playlist and goes on air when no encoder is delivering. It is the fill tier, not a channel you can programme a day of content into
Multi-input compositing / video grid 1 reaction Missing. Natural once multi-source is settled
MQTT Core tracker Have. Retained telemetry with Home Assistant discovery, so the stream appears as entities in a dashboard the operator already runs. Alert webhooks exist alongside it — see MQTT.md
HDR 10-bit HEVC 3 reactions, closed Partial. libx265 and hevc_nvenc exist; no HDR tone-map path
LL-HLS 2 reactions, closed Addressed by tuning, not by building LL-HLS. FFmpeg cannot emit LL-HLS partial segments at all — verified against the pinned binary — so the protocol would need a Go-side packager, which roadmap/LL-HLS.md declines. Tuning instead took preview latency from 4.2–6.2 s to 2.2–3.2 s, measured. Two of the wins were bug fixes rather than knobs: a wrong GOP calculation, and a player flag that was inert because of an unrelated default
Maturity Restreamer is established; polyemesis is pre-release with one maintainer

One caveat on Restreamer's side. Two of its four most-reacted open issues are not feature requests — "State of Restreamer" (31 reactions) and "Future release plans? (last release September 2024)" (11). Roughly a fifth of the open tracker's reaction weight is users asking whether the project is alive. That is context for the maturity row, not a criticism of the software.

What MistServer has that polyemesis does not

MistServer (Unlicense, ~508 stars, last pushed 2026-08-06, checked 2026-08-09) is the one tool here that is a peer rather than a different shape: a media server that ingests and pushes out, and does it at a scale and protocol breadth this project does not approach.

What it has polyemesis
Protocol breadth — an src/output/ directory of muxers, including WebRTC and its own SRT output SRT and RTMP in, RTMP/SRT out, HLS for preview
Per-push track selection, on any target, by index or codec or all Selection is per destination too, but the point here is the mix
Years of production deployment, and a commercial vendor behind it Pre-release, one maintainer
Selection without decoding. A push target that only selects tracks is a pure copy end to end; transcoding is a separate opt-in process Every destination decodes and re-encodes its audio, always, because that is what mixing is

A caveat on reading their source. The track-selection block in Util::wouldSelect sits between /*LTS-START*/ and /*LTS-END*/ comment markers. Those are plain comments, not preprocessor guards, and nothing in meson.build or meson_options.txt strips them, so the code compiles in the Unlicense repository as published (checked 2026-08-09). Whether every binary DDVTECH distributes includes it is unverified — check before you depend on it.

What restream.io has that polyemesis does not

restream.io is SaaS, so self-hosting beats it on cost, privacy and limits by construction — their plans cap simultaneous channels at 2 free, 3 standard and 5 professional (competitor-facts §2.D, checked 2026-08-15), which is a billing artefact rather than a technical one. This said "2/3/5/8" until 2026-08-15; the fourth number was wrong and contradicted the site's own table.

restream.io feature polyemesis
Studio — browser production, remote guests Missing. Multi-source plus compositing is the closest path
Pre-recorded upload, go live later Have. Upload the file, it is normalised on import, and a scheduled playlist.start puts it on air at a chosen time. Needs the failover tier on, since that is where the playlist lives
Teams, roles, multiple workspaces Missing. Exactly one admin identity
Webinars — private, attendee caps, Slack delivery (+$99–299/mo) Missing. No webinar mode. A private destination plus the built-in chat is the closest path
Website player — embeddable, 1000 viewers (Business) Missing. The HLS preview is operator-facing and auth-gated; there is no public player route
Guest/paired channels — guests attach their own destinations to your event Missing. Follows from the single admin identity
Automatic clip selection — "TikTok-ready clips" (+$19–59/mo) Partial. internal/clipper cuts keyframe-accurate clips from the archive and internal/clips holds a live 30-second ring buffer — but an operator picks the in and out points. The missing half is automatic highlight selection, not clipping
Dual format — vertical and horizontal at once (Professional, $49/mo) Have. A rendition takes an explicit width×height with AspectCrop (centre-crop) or AspectBlurredPad; a 1080x1920 preset ships. internal/ffmpeg/rendition.go:61
SRT ingest (enterprise only — "book a demo") Have, and it is the primary operated ingest path
Stream backup (enterprise only — "book a demo") Have, and the implementation is the stronger one — see below
Hosted chat across platforms Have, self-hosted
Live health monitor Have
No server to run By design, no

The seven rows above were added 2026-08-25 from restream.io's live pricing page. Four are gaps this table had missed entirely; three are capabilities polyemesis already had and this document was not crediting — dual format and SRT ingest are priced features there, and stream backup is behind "book a demo".

On stream backup specifically. Restream's is a hosted safety net. polyemesis's source-selector tier (internal/engine/selector.go) is a different and stronger shape: destinations subscribe to a permanent hub whose identity never changes, and only the feed into it is switched — primary, standby ingest, a looping playlist file, then the slate. The platform connection is therefore never dropped when the encoder disappears, which is the failure the whole tier exists to prevent. It is OFF by default (failover.enabled), which is its real weakness — see issue #512.

Teams and roles is the one to take seriously. polyemesis has a single admin identity, and access to the UI is full control of the server's streaming. Any multi-operator deployment — a church A/V team, an agency running several clients — hits that immediately. See ../SECURITY.md.

Where the servers overlap

All of them do the basic job: ingest once, fan out to several platforms, reconnect when a platform drops, show you whether it is working.

polyemesis Restreamer restream.io MistServer
Self-hosted Yes Yes No Yes
Simultaneous destinations No configured cap1 not assessed 2–5 by plan tier (checked 15 Aug 2026) Unverified
Video re-encoded per destination No (-c:v copy) Optional Yes, server-side Optional, as a process
Recording Multitrack, stream-copied No built-in2 Yes Yes, tracks selectable
Unified chat Yes not assessed not assessed not assessed
Metrics / API Prometheus + REST See4 REST REST
Hardware encoding NVENC, QSV, VA-API, VideoToolbox, AMF5 Yes n/a NVENC
Public release in the last 12 months Yes3 No3 n/a, hosted Yes3
Cost Your hardware Your hardware Subscription Your hardware

1 No limit in the software. Upload bandwidth and CPU are the real ones: measured at roughly 4% of one core per destination on a 6-core VPS, so a 4-core box runs out somewhere near 96. "Unlimited" was the previous wording and it was not defensible.

2 This row said "Yes" until 2026-08-09 and was wrong. Recording is an open feature request on Restreamer's own tracker — datarhei/restreamer#692, opened 2024-02-14, still open when checked 2026-08-09. The underlying datarhei Core can write files; the Restreamer product does not put recording in front of you, which is why the request exists.

3 Release recency, not quality, and it cuts against the maturity row above rather than replacing it. Restreamer's latest release is v2.12.0, 2024-09-13. MistServer's repository was last pushed 2026-08-06. polyemesis tagged v0.1.0 on 2026-07-31 and v0.6.0 on 2026-08-09 — which is the velocity of something pre-release with one maintainer, and is worth exactly that much. All three checked 2026-08-09.

4 This row said "No" against Restreamer and that was wrong. Restreamer mounts a filter select per publication service, and loudnorm is one of the filters it offers, so it does apply a per-destination loudness filter. What it does not offer is a target you set: its control is an on/off checkbox that emits the bare string loudnorm with no I, LRA or TP, so it takes FFmpeg's defaults and an operator cannot ask for −16 LUFS rather than −24. That is the real difference and it is narrower than the row used to claim. Corrected 2026-08-14 after a sweep read their source rather than their feature list — the same correction the recording row needed in the other direction, and the second time a cell here has asserted a competitor lacks something they ship.

The metrics row above was wrong the same way and is now blank on their side: Restreamer's own README advertises resource monitoring "optionally by Prom-Metrics", datarhei Core documents Prometheus support, and it serves GraphQL as well as REST — so "REST" understated them twice over and implied Prometheus was ours alone.

5 All five are offered and all five are probed with a real one-frame encode at startup, so an encoder that is listed but unusable is caught before a broadcast is. What is EXPERIMENTAL is narrower: the per-encoder command-line flags handed to NVENC, QSV, VA-API and AMF — rate control, preset, profile — were read out of FFmpeg's own option tables rather than measured on silicon, and no such encode has been observed. VideoToolbox is not in that set: TestEveryConfiguredEncoderOpensWithItsOwnFlags runs a real encode per registered encoder with that encoder's own flags and both VideoToolbox rows pass. See ENCODING.md § Per-encoder flags.


See also

Clone this wiki locally