Skip to content

Instantly share code, notes, and snippets.

@onyx-nxt
Last active December 26, 2025 09:59
Show Gist options
  • Select an option

  • Save onyx-nxt/750578ac505dc3560ea80c15bb21112b to your computer and use it in GitHub Desktop.

Select an option

Save onyx-nxt/750578ac505dc3560ea80c15bb21112b to your computer and use it in GitHub Desktop.
MPV script that fixes video sync on some broken videos where both the audio and video PTS are incorrect by a constant factor. This is appearent on some videos exported from Topaz VEAI from the looks of it. This essentially works by measuring how much frames drop due to display sync and calculating the correct video fps and changes it via the set…
local mp = require 'mp'
function fix_sync()
-- Capture the first snapshot
local start_dropped = mp.get_property_number("mistimed-frame-count") or 0
local fps = mp.get_property_number("container-fps") or 0
if fps == 0 then return end
mp.add_timeout(1, function()
-- Capture the second snapshot
local end_dropped = mp.get_property_number("mistimed-frame-count") or 0
local drops_per_second = end_dropped - start_dropped
local dps_threshold = fps * 0.5
-- If no significant portion of frames were dropped, no need to adjust
if drops_per_second <= dps_threshold then
return
end
local override_fps = fps + drops_per_second
local raw_multiplier = fps / override_fps
local pts_multiplier = math.floor(raw_multiplier * 10 + 0.5) / 10
-- Apply settings to compensate for drop rate
mp.commandv("vf", "add", "@sync:setpts=".. pts_multiplier .."*PTS")
mp.commandv("af", "add", "@sync:asetpts=" .. pts_multiplier .. "*PTS")
mp.msg.info("Sync fix applied: A/V PTS multiplier set to " .. pts_multiplier)
end)
end
mp.register_event("file-loaded", function()
-- Reset any previous adjustments
mp.command("no-osd vf remove @sync")
mp.command("no-osd af remove @sync")
if mp.get_property_bool("pause") == false then
-- If already playing, start the sync fix
mp.add_timeout(1, fix_sync)
else
-- If paused, wait for unpause. We need the video to be playing to measure drops
local function wait_for_start(name, paused)
if paused == false then
-- The video is playing, start the sync fix
mp.unobserve_property(wait_for_start)
mp.add_timeout(1, fix_sync)
end
end
mp.observe_property("pause", "bool", wait_for_start)
end
end)
@onyx-nxt
Copy link
Author

onyx-nxt commented Dec 24, 2025

Full description:

MPV script that fixes video sync on some broken videos where both the audio and video PTS are incorrect by a constant factor. This is appearent on some videos exported from Topaz VEAI from the looks of it. This essentially works by measuring how much frames drop due to display sync and calculating the correct video fps and changes it via the setpts video filter, as well as audio via asetpts. Requires video-sync=display-*. To get a more accurate drop rate reading, a timeout is induced, meaning it'll take 2 seconds to actually take effect. On normal videos, they are left alone. It's activation rule is when the frames dropped per second is more than 50% of the container frame rate. In most cases, this is enough.

@onyx-nxt
Copy link
Author

onyx-nxt commented Dec 24, 2025

Also this does not work with both video-sync=display-* and the asetpts=N/SR/TB af filter. Just remove that asetpts, its useless with this script.

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