Jellyfin MPV Shim 2.x Legacy Guide: Direct Paths, HDR & Zero Transcoding

Update – October 2026: This article covers Jellyfin MPV Shim 2.x, including the final 2.10.x releases. MPV Shim 3.0 substantially redesigned the client with a built-in library browser, new playback settings, offline sync, Live TV, Jellyfin 12 support, new audio controls, and many configuration changes. If you are installing or upgrading to MPV Shim 3.x, the configuration on this guide is still working for me, but be aware I did not test any new features from 3.x yet (but also did not notice any issues). This legacy guide remains here for users intentionally staying on 2.x and as a reference for older installations.

If you already have a high-end mpv setup working correctly, the next bottleneck is usually not the renderer. It is the layer that decides whether mpv opens the original file directly or whether Jellyfin pushes playback through a weaker path first. That is where Jellyfin MPV Shim matters.

For a quality-first home theater setup, the most important job of `conf.json` is not cosmetic customization. It is keeping playback aligned with what the local system already does well: direct file access, local decoding, local HDR handling, Dolby Vision-aware handling, and AVR audio passthrough. If the shim prefers transcoding or gets in the way of local file access, the quality ceiling drops immediately.

This guide focuses only on the settings that materially affect that outcome. It is based on source-level behavior, real playback logs, and a tuned Windows mpv pipeline rather than generic Jellyfin client advice.

This Jellyfin MPV Shim guide builds on a properly configured mpv setup.

If you haven’t configured mpv yet, start with the main Best mpv config 2026, which also includes platform-specific notes.

TL;DR

– Enable `direct_paths` → highest quality playback
– Use `path_substitutions` → map server paths to local files
– Disable:
– `transcode_hdr`
– `transcode_dolby_vision`
– Max out `local_kbps` / `remote_kbps`(assuming your local connection can sustain high speed transfers required for 4K / HDR / 60 FPS)
– Let mpv handle rendering, HDR, and audio

What this article is about and what it is not

This is a guide to `conf.json` for Jellyfin MPV Shim, not a guide to the whole mpv render stack. The core mpv renderer, HDR policy, Dolby Vision-aware profile logic, and AVR audio decisions belong in `mpv.conf` or, in my case, the Best mpv config 2026.

The shim exists one layer above that. Its concern is playback selection, path handling, client behavior, and whether it cooperates with your existing mpv configuration.

That distinction matters because many people try to solve shim problems with mpv options and mpv problems with shim options. Those are different layers, and the best results come from giving each layer a narrower job.

The core principle: direct paths beat transcode-first behavior

For maximum quality, the best playback path is usually the most boring one:

1. Jellyfin identifies the original media source.
2. The shim resolves that source to a locally accessible path.
3. mpv opens the actual file directly.
4. Your local mpv configuration handles video, HDR, Dolby Vision-aware logic, subtitles, and audio passthrough.

That is the right model for a system with a tuned local mpv configuration because it avoids server-side video conversion, server-side audio conversion, HLS instability, and browser-style compatibility fallbacks.

That is why direct paths are used here. When the client machine already has local file access and a tuned mpv stack, they provide the better playback experience.

Why direct paths produce a better playback experience

The quality benefits of direct paths is straightforward.

First, direct paths preserve the original file container and streams instead of asking the server to prepare an alternate delivery path. That matters for high-bitrate remuxes, HDR titles, Dolby Vision profile fallback cases, and premium audio tracks.

Second, direct paths avoid a failure class that appears in real-world shim usage: the server exposes an HLS transcode URL, the client opens it, and the stream is less stable or fails outright. In my own testing, that weaker path ended in HTTP 500 errors. The direct-path case handed mpv the file itself and played cleanly.

Third, direct paths hand control back to the local player. If your system is already configured for gpu-next, D3D11, HDR-aware profiles, Dolby Vision-aware handling, and AVR-friendly audio passthrough, that is exactly what you want.

If your system can reach the underlying media files directly, `direct_paths` should be enabled. That is the single most important `conf.json` decision for a quality-first setup.

With `direct_paths=true`, the shim attempts to resolve the media source to a path mpv can open directly rather than defaulting to a network stream or transcode URL. In practice, that gives you a cleaner handoff into your local playback chain.

If you disable it, you are more likely to end up treating Jellyfin MPV Shim like a browser client with a nicer player attached. That is not what you want on a serious local playback machine.

`remote_direct_paths` is sometimes misunderstood because people read it as a mobile or truly internet-remote feature. In reality, the meaningful question is whether the client can still access the source path in the environment where it is being used.

For a home setup where the client can still see the same mapped storage, it is reasonable to enable this as well to make sure everything works.

Why path rewriting matters so much

Newer releases of Jellyfin removed the ability of specifying the file path, so if you have a mixed environment (e.g. Jellyfin on Docker and mpv-shim on Windows), path rewriting is critical.

Jellyfin often knows the media source by a server-side path that is not usable on the client as-is. Example, if the server sees `/data/media/movies/Foo.mkv` and the Windows client actually needs `Z:\media\movies\Foo.mkv`, the shim has to translate one view of the library into the other.

Path substitutions in MPV Shim 2.10

path_substitutions was originally functionality I used through a fork, but it was subsequently included upstream in Jellyfin MPV Shim 2.10. If Jellyfin sees a file as /data/media/movies/Foo.mkv while your Windows playback machine sees it as Z:\media\movies\Foo.mkv, a substitution lets the shim translate between the two paths.

"path_substitutions": [
  ["/data/media", "Z:\\media"]
]

This is particularly useful when Jellyfin runs in Docker or on another operating system while MPV Shim runs on Windows.

Why transcode_hdr should be off in a tuned mpv setup

If your local mpv configuration already handles HDR correctly, `transcode_hdr` should usually be disabled.

That is not an anti-HDR position. It is the opposite. A high-end local mpv chain is usually better at handling HDR than a forced server-side transcode path.

Once Jellyfin starts converting HDR content on the server, you are no longer testing the quality of your local renderer path. You are testing how well the server can flatten or repack the source into something more generic. For a system designed around mpv, that is a downgrade.

Why transcode_dolby_vision should also be off here

The same logic applies even more strongly to `transcode_dolby_vision`.

mpv is not a native Dolby Vision output stack in the same sense as device-certified playback apps, but a tuned local mpv path can still do more useful things with Dolby Vision files than a generic transcode path that strips the source down to something broadly compatible.

A quality-first example conf.json

This is an example of a quality-first Jellyfin MPV Shim config for a system that can reach the media files directly and already has a tuned mpv stack. Keep defaults but modify these:

  "direct_paths": true,
  "enable_osc": true,
  "local_kbps": 2147483,
  "remote_direct_paths": true,
  "remote_kbps": 2147483,
  "shader_pack_enable": false,
  "thumbnail_enable": false,
  "transcode_dolby_vision": false,
  "transcode_hdr": false,
  "path_substitutions": [
    ["/data/media", "Z:\\media"]
  ]

What to keep in mpv and what to keep in the shim

This separation is the best way to keep the setup understandable.

Put these decisions in mpv:

– renderer choice
– hardware decode choice
– HDR policy
– Dolby Vision-aware profile logic
– HDR10+ handling
– audio passthrough behavior

Put these decisions in the shim:

– direct path behavior
– path rewriting
– transcode avoidance policy
– basic UI and client behavior
– whether shim-managed shader packs are allowed at all

Who should use this kind of conf.json

This style of config is right for you if the following are true:

– your client machine can access the original media files directly
– your mpv config is already tuned and trusted
– your priority is original-file playback quality, not generic compatibility
– your setup includes HDR-capable playback and an AVR-friendly audio chain
– your setup benefits from path rewriting because the server and playback machine use different filesystem paths

If your client cannot access the real media files, if your environment changes between locations, or if your system is better served by normal Jellyfin streaming rather than filesystem-level direct access, do not copy this configuration line for line.

Who should not use this

If your client cannot access the real media files, if your environment changes between locations, if you rely on the stock upstream behavior without fork-specific path substitution support, or if your system is better served by more generic compatibility behavior, then you should not copy this config line for line.

The logic matters more than the literal values. The reason this setup works is that the architecture matches the environment.

Final thoughts

The best Jellyfin MPV Shim configuration is the one that does the least.

If your system already has:
– direct file access
– a tuned mpv renderer
– proper HDR handling
– AVR passthrough

Then the shim should not reinterpret, convert, or “improve” anything. It should simply hand the file to mpv. That is what this configuration achieves.

Legacy configuration: The full configuration below is preserved specifically as an MPV Shim 2.x example. Do not copy it into MPV Shim 3.x without testing (for me it works fine though); several settings might be renamed, migrated to input.conf, removed, or replaced by the new Settings UI. I did not get a chance to fully explore this yet.

{
    "allow_transcode_to_h265": false,
    "always_transcode": false,
    "auto_play": true,
    "check_updates": true,
    "client_uuid": "",
    "connect_retry_mins": 0,
    "direct_paths": true,
    "discord_presence": false,
    "display_mirroring": false,
    "enable_gui": true,
    "enable_osc": true,
    "force_audio_codec": null,
    "force_set_played": false,
    "force_video_codec": null,
    "fullscreen": true,
    "health_check_interval": 300,
    "idle_cmd": null,
    "idle_cmd_delay": 60,
    "idle_ended_cmd": null,
    "idle_when_paused": false,
    "ignore_ssl_cert": false,
    "kb_debug": "~",
    "kb_fullscreen": "f",
    "kb_kill_shader": "k",
    "kb_menu": "c",
    "kb_menu_down": "down",
    "kb_menu_esc": "esc",
    "kb_menu_left": "left",
    "kb_menu_ok": "enter",
    "kb_menu_right": "right",
    "kb_menu_up": "up",
    "kb_next": ">",
    "kb_pause": "space",
    "kb_prev": "<",
    "kb_stop": "q",
    "kb_unwatched": "u",
    "kb_watched": "w",
    "lang": null,
    "lang_filter": "und,eng,jpn,mis,mul,zxx",
    "lang_filter_audio": false,
    "lang_filter_sub": false,
    "local_kbps": 2147483,
    "log_decisions": true,
    "media_ended_cmd": null,
    "media_key_seek": false,
    "media_keys": true,
    "menu_mouse": true,
    "mpv_ext": false,
    "mpv_ext_ipc": null,
    "mpv_ext_no_ovr": false,
    "mpv_ext_path": null,
    "mpv_ext_start": true,
    "mpv_log_level": "info",
    "notify_updates": true,
    "play_cmd": null,
    "playback_timeout": 30,
    "player_name": "Theater",
    "pre_media_cmd": null,
    "prefer_transcode_to_h265": false,
    "raise_mpv": true,
    "remote_direct_paths": true,
    "remote_kbps": 2147483,
    "sanitize_output": true,
    "screenshot_dir": "C:\\Users\\Theater\\Desktop",
    "screenshot_menu": true,
    "seek_down": -60,
    "seek_h_exact": false,
    "seek_left": -5,
    "seek_right": 5,
    "seek_up": 60,
    "seek_v_exact": false,
    "shader_pack_custom": false,
    "shader_pack_enable": false,
    "shader_pack_profile": null,
    "shader_pack_remember": true,
    "shader_pack_subtype": "hq",
    "skip_credits_always": false,
    "skip_credits_enable": true,
    "skip_intro_always": false,
    "skip_intro_enable": true,
    "stop_cmd": null,
    "stop_idle": false,
    "subtitle_color": "#808080",
    "subtitle_position": "bottom",
    "subtitle_size": 70,
    "svp_enable": false,
    "svp_socket": null,
    "svp_url": "http://127.0.0.1:9901/",
    "sync_attempts": 5,
    "sync_max_delay_skip": 300,
    "sync_max_delay_speed": 50,
    "sync_method_thresh": 2000,
    "sync_osd_message": true,
    "sync_revert_seek": true,
    "sync_speed_attempts": 3,
    "sync_speed_time": 1000,
    "thumbnail_enable": false,
    "thumbnail_osc_builtin": false,
    "thumbnail_preferred_size": 320,
    "tls_client_cert": null,
    "tls_client_key": null,
    "tls_server_ca": null,
    "transcode_4k": false,
    "transcode_av1": false,
    "transcode_dolby_vision": false,
    "transcode_hdr": false,
    "transcode_hevc": false,
    "transcode_hi10p": false,
    "transcode_warning": true,
    "use_web_seek": false,
    "write_logs": true,
    "path_substitutions": [
      ["/data/media", "Z:\\media"]
    ]
}

1 Trackback or Pingback

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.