Skip to content

Streams play as speckle noise — decode ruled out on local files; leading suspect is damaged bytes on the debrid stream path #229

Description

@cubman3134

Reported from use with a screenshot: many movie/TV streams play as dense coloured speckle noise with
horizontal streaking over a dark image. Subtitles render perfectly on top, so the render path is fine —
the decoded frames are corrupt. It affects many streams, so it is systematic, not the content.

What the log says the player actually did

16:07:44  mpv: hwdec requested='auto-safe' (setting=auto)
16:10:17  video: codec='H.264 / AVC …'  1920x798  pixfmt=cuda  hwdec-current=nvdec
16:20:47  mpv: hwdec requested='auto-safe' (setting=auto)
16:21:31  video: codec='H.265 / HEVC …'  1620x1080 pixfmt=cuda  hwdec-current=nvdec

hwdec-current=nvdec, pixfmt=cuda, on both an H.264 and an HEVC stream. That is nvdec direct: CUDA
frames handed to OpenGL through CUDA↔GL interop, not copied back to system memory.

The design assumption this contradicts

HwDecode.h and Settings.h document why auto is the default:

Auto = "auto-safe" (copy-back preferred, software fallback) is deliberately the default — it sidesteps
the D3D11VA 10-bit-HEVC corruption that made a blanket "no" the original hard-coded choice.

The intent is clearly copy-back. But mpv's auto-safe is a whitelist of decoders mpv considers safe,
and on an NVIDIA machine that whitelist includes nvdec direct — so auto-safe does not deliver
copy-back here. It delivers the interop path, and the interop path is what is corrupting frames.

This is a different failure from the one the comment remembers. That one was D3D11VA on 10-bit HEVC.
This one is nvdec interop on ordinary 8-bit H.264 and HEVC, through a Qt QOpenGLWidget context
(MPV_RENDER_API_TYPE_OPENGL, MpvWidget.cpp).

Corroborating evidence

  • crash_report.log, 2026-08-25 16:12: a fatal 0xc0000005 inside nvoglv64.dll (the NVIDIA OpenGL
    driver) on a driver thread — the same GL path under load.
  • The themed UI is deliberately software-rendered because of "an mpv GL conflict" (documented in
    main.cpp). GL sharing with mpv on this machine has form.

The fix to establish, not assume

mpv has hwdec=auto-copy-safe — the same safe whitelist, copy-back variants only — which is what
the design comment describes wanting. Mapping the auto choice to auto-copy-safe instead of
auto-safe would deliver the documented intent. Costs one frame copy per frame; on modern hardware
that is not a visible cost at these resolutions, and it removes the interop entirely.

Establish it empirically before shipping: the same stream under hwdec=nvdec (expect corruption),
nvdec-copy (expect clean), no (expect clean, baseline), and auto-copy-safe (expect clean and
hwdec-current=nvdec-copy). The log line at MpvWidget.cpp:503 already prints hwdec-current, so the
evidence is one grep per run.

Also check what auto-copy-safe resolves to on a machine without NVIDIA — the fix must not regress
D3D11VA-copy or Android's mediacodec-copy, both of which HwDecode.h reasons about explicitly.

Immediate workaround for a user

Settings → Video → hardware decoding → Off (video/hwdec=off). Guaranteed-correct software decode,
higher CPU. Flipping it and watching the corruption stop is also the cheapest confirmation of this
diagnosis.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions