mirror of https://github.com/mpv-player/mpv
skip-logo.lua: fix skipping in the first two frames
mpv typically decodes and filters at least 2 frames before starting playback. This happens during seeks, as well as when playback starts from the beginning of the file. skip-logo.lua receives notifications for all filtered frames, even during seeking. It should interrupt during seeking, so as a crude heuristic, it ignored all frames while the player was seeking. This does not mean all these frames are skipped due to seeking (thus it's a "crude hueristic"). In particular, it means that the first 2 frames of a video cannot be skipped, since they're filtered within the playback restart phase (equivalent to "seeking"). Fix this by making the heuristic slightly less crude. Since we observe the property as "none", the property is not actually read until we do it explicitly. By not reading it during seeking, we can let the frames internally queue up (vf_fingerprint discards them in a ringbuffer-like fashion if they're too many). Then, if seeking ends, we get the current playback timestamp, and check queued up frames that are at or after that timestamp. (In some ways, this duplicates what the player's seeking logic does.) A disadvantage is that this is racy. While playback-time is guaranteed to be set when seeking changes from false to true, playback could already have progressed to the next frame (or more) before the script gets time to react. In theory, we could add a seek restart hook or so, but I don't want to. A property that returns the last playback restart time would also do it, but feels to special. Not an important problem in practice anyway.
This commit is contained in:
parent
0a30a4a432
commit
68bbc55eda
|
@ -79,6 +79,8 @@ local meta_property = string.format("vf-metadata/%s", label)
|
||||||
local config = {}
|
local config = {}
|
||||||
local cases = {}
|
local cases = {}
|
||||||
local cur_bmp
|
local cur_bmp
|
||||||
|
local seeking = false
|
||||||
|
local playback_start_pts = nil
|
||||||
|
|
||||||
-- Convert a hex string to an array. Convert each byte to a [0,1] float by
|
-- Convert a hex string to an array. Convert each byte to a [0,1] float by
|
||||||
-- interpreting it as normalized uint8_t.
|
-- interpreting it as normalized uint8_t.
|
||||||
|
@ -194,24 +196,12 @@ local function check_fingerprint(hex, pts)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
mp.observe_property(meta_property, "none", function()
|
local function read_frames()
|
||||||
local result = mp.get_property_native(meta_property)
|
local result = mp.get_property_native(meta_property)
|
||||||
if result == nil then
|
if result == nil then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Disable matching while seeking. This is not always ideal. For example,
|
|
||||||
-- the filter chain may filter frames ahead of where it will resume
|
|
||||||
-- playback (if something prefetches frames). On the other hand, the
|
|
||||||
-- skipping logic shouldn't activate when the user is trying to seek past
|
|
||||||
-- the skip frame anyway. You could be more fancy and here, and store all
|
|
||||||
-- seen frames, then apply the skipping when it's actually displayed (by
|
|
||||||
-- observing the playback time). But for now, the naive and not-always-
|
|
||||||
-- correct way seems to suffice.
|
|
||||||
if mp.get_property_bool("seeking", false) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Try to get all entries. Out of laziness, assume that there are at most
|
-- Try to get all entries. Out of laziness, assume that there are at most
|
||||||
-- 100 entries. (In fact, vf_fingerprint limits it to 10.)
|
-- 100 entries. (In fact, vf_fingerprint limits it to 10.)
|
||||||
for i = 0, 99 do
|
for i = 0, 99 do
|
||||||
|
@ -223,9 +213,40 @@ mp.observe_property(meta_property, "none", function()
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|
||||||
if check_fingerprint(hex, pts) then
|
local skip = false -- blame Lua for not having "continue" or "goto", not me
|
||||||
break
|
|
||||||
|
-- If seeking just stopped, there will be frames before the seek target,
|
||||||
|
-- ignore them by checking the timestamps.
|
||||||
|
if playback_start_pts ~= nil then
|
||||||
|
if pts >= playback_start_pts then
|
||||||
|
playback_start_pts = nil -- just for robustness
|
||||||
|
else
|
||||||
|
skip = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if not skip then
|
||||||
|
if check_fingerprint(hex, pts) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mp.observe_property(meta_property, "none", function()
|
||||||
|
-- Ignore frames that are decoded/filtered during seeking.
|
||||||
|
if seeking then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
read_frames()
|
||||||
|
end)
|
||||||
|
|
||||||
|
mp.observe_property("seeking", "bool", function(name, val)
|
||||||
|
seeking = val
|
||||||
|
if seeking == false then
|
||||||
|
playback_start_pts = mp.get_property_number("playback-time")
|
||||||
|
read_frames()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue