-
Notifications
You must be signed in to change notification settings - Fork 0
Custom Patches
This build system supports applying custom patches to FFmpeg and mpv
source before compiling, via CUSTOM_PATCH_DIR. This page documents the
mechanism and the patches currently shipped with this project.
CUSTOM_PATCH_DIR must contain two subdirectories:
CUSTOM_PATCH_DIR/
├── ffmpeg/
│ └── *.patch
└── mpv/
└── *.patch
Every .patch file found is applied via patch -p1 against the
respective source tree before building. Patches are applied in
alphabetical order.
CUSTOM_PATCH_DIR=~/patches ./build-libmpv-mingw64.sh v0.41.0Windows (build-libmpv-mingw64.sh): supported natively — this is where these patches were developed and tested.
Linux / macOS build scripts: not yet verified to support this
mechanism. If you need patch support on those platforms, check whether
your copy of build-libmpv-linux.sh / build-libmpv-linux-next.sh /
build-libmpv-macos.sh has an equivalent apply_patches() function
before assuming this works there.
A patch can optionally declare a minimum version it applies to, via a header comment on one of its first few lines:
# min-version: 0.40.0
--- a/player/playloop.c
+++ b/player/playloop.c
...If the version being built doesn't meet the requirement, the patch is
skipped — loudly, logged, not silently — rather than either failing to
apply (which aborts the build) or, worse, applying somewhere it was
never verified against. This matters because several of the patches
below depend on source structure that only exists from v0.40.0 onward;
reusing the same CUSTOM_PATCH_DIR to build an older tag (e.g.
v0.37.0) alongside v0.41.0 would otherwise be unsafe.
The comment line doesn't interfere with patch's own parsing — patch
already ignores anything before the --- a/... line.
Patches with no min-version header apply unconditionally to every
version built.
| Patch | Fixes |
|---|---|
mpegvideo_parser_resync_valve.patch |
Bounds mpeg1_find_frame_end's parser state — without this, malformed/unusual MPEG-2 streams could cause the parser's internal buffer to grow without ever finding a frame boundary. Adds an 8MiB safety valve that forces a resync if no frame boundary is found within that window. |
combine_frame_shrink.patch |
ff_combine_frame's internal buffer (pc->buffer) grows to accommodate the largest frame seen, but was never shrunk back down afterward. Proactively frees and resets it once it's no longer needed, instead of holding the high-water-mark size for the rest of the session. |
Both were found and confirmed via targeted diagnostic instrumentation during a memory investigation — not merely theoretical; both showed measurable effect on real content.
| Patch | Min version | Fixes |
|---|---|---|
idle_packet_pool_clear.patch |
0.40.0 | Backport of upstream commit 4a815734e3d183dc63fecc08b8f9f8c396c53647 ("player/playloop: clear demux packet pool on idle"). The demux packet pool is deliberately kept populated across file switches (avoids reallocation cost), but was never cleared when mpv genuinely goes idle (no file queued) — meaning it just sat at its high-water-mark indefinitely. Requires idle=yes to actually reach the code path this touches (see note below). |
pool_incremental_gc.patch |
0.40.0 | Backport of upstream commit 09900a0ff016c24409a4e6f95012260ed1107d7e ("demux/packet_pool: incrementally free old packets on pop"), upstream PR #17889. Unlike the idle-clear patch above, this one works during normal, active playback — every packet-pool pop call now also frees a small batch of excess pooled packets, so the pool self-balances continuously rather than only shrinking when idle. Doesn't depend on idle=yes. Fixes upstream issue #17323 ("memleak watching hls tv streams"). |
fence_leak_fix.patch |
0.40.0 | Backport of upstream commit f74adc4243bd9e1a8ee96d187c939e6232510650 ("opengl/context: require swap_buffers param for FenceSync"), fixes upstream #17217. vo_libmpv (the embedded Render API backend — used by any application driving mpv_render_context_render() directly, as opposed to the standalone mpv player) leaked one GLsync fence object into a heap-allocated array on every single render call, since the function that normally consumes/frees them is never invoked for this backend. This was often the single largest contributor to memory growth of everything found — confirmed against a real, independently-reported upstream issue with matching symptoms (heap growth specific to repeated mpv_render_context_render() calls, confirmed via VMMap to be heap memory, not GPU-driver memory). |
None of the three mpv patches are present in v0.37.0 or v0.38.0 — the
underlying refactors they build on (demux/packet_pool.c's
introduction, and the swapchain-API changes the fence fix responds to)
postdate those releases. The min-version: 0.40.0 header on each
patch enforces this automatically.
idle=yes note: idle_packet_pool_clear.patch only has an effect
if the mpv instance actually has player_idle_mode enabled — libmpv's
default is no. Without it, the code path this patch touches never
runs at all. If you're embedding libmpv and want this fix to matter,
set mpv_set_option_string(mpv_, "idle", "yes") (or the equivalent in
your mpv.conf) during initialization. Testing showed no effect on
active playback or channel-change behavior — the idle-loop path is
only reached when nothing is queued to play next, and mpv's own event
wakeup (mp_wakeup_core) correctly resumes immediately once a new
loadfile command arrives.
Download from the wiki repo alongside the SDK/runtime tarballs:
| File | Link |
|---|---|
mpegvideo_parser_resync_valve.patch |
download |
combine_frame_shrink.patch |
download |
idle_packet_pool_clear.patch |
download |
pool_incremental_gc.patch |
download |
fence_leak_fix.patch |
download |
(These links assume the patch files are added to the wiki repo the same way the SDK/runtime tarballs are — clone the wiki locally, add the files, commit and push. See the "Clone this wiki locally" link on any wiki page.)
The build script's stamp-based caching only tracks mpv/FFmpeg version and the debug-symbols flag — it does not detect changes to patch file contents. If you add, remove, or edit a patch and rerun the build without clearing the relevant cached tree, the stale build will be reused silently, with the old patch set (or no patches at all) still in effect.
Force a clean rebuild whenever the patch set changes:
rm -rf work/deps-ffmpeg7 # or deps-ffmpeg6, matching the FFmpeg version affected
git -C work/src/ffmpeg reset --hard
git -C work/src/ffmpeg clean -fdFor mpv itself, build_libmpv_tag() already does a full git reset --hard / git clean -fd before reapplying patches on every run, so
no manual step is needed there — only the FFmpeg side has this
caching gap.