diff options
Diffstat (limited to 'TOOLS/lua/autodeint.lua')
-rw-r--r-- | TOOLS/lua/autodeint.lua | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/TOOLS/lua/autodeint.lua b/TOOLS/lua/autodeint.lua new file mode 100644 index 0000000..b891c9a --- /dev/null +++ b/TOOLS/lua/autodeint.lua @@ -0,0 +1,156 @@ +-- This script uses the lavfi idet filter to automatically insert the +-- appropriate deinterlacing filter based on a short section of the +-- currently playing video. +-- +-- It registers the key-binding ctrl+d, which when pressed, inserts the filters +-- ``vf=idet,lavfi-pullup,idet``. After 4 seconds, it removes these +-- filters and decides whether the content is progressive, interlaced, or +-- telecined and the interlacing field dominance. +-- +-- Based on this information, it may set mpv's ``deinterlace`` property (which +-- usually inserts the yadif filter), or insert the ``pullup`` filter if the +-- content is telecined. It also sets field dominance with lavfi setfield. +-- +-- OPTIONS: +-- The default detection time may be overridden by adding +-- +-- --script-opts=autodeint.detect_seconds=<number of seconds> +-- +-- to mpv's arguments. This may be desirable to allow idet more +-- time to collect data. +-- +-- To see counts of the various types of frames for each detection phase, +-- the verbosity can be increased with +-- +-- --msg-level=autodeint=v + +require "mp.msg" + +script_name = mp.get_script_name() +detect_label = string.format("%s-detect", script_name) +pullup_label = string.format("%s", script_name) +dominance_label = string.format("%s-dominance", script_name) +ivtc_detect_label = string.format("%s-ivtc-detect", script_name) + +-- number of seconds to gather cropdetect data +detect_seconds = tonumber(mp.get_opt(string.format("%s.detect_seconds", script_name))) +if not detect_seconds then + detect_seconds = 4 +end + +function del_filter_if_present(label) + -- necessary because mp.command('vf del @label:filter') raises an + -- error if the filter doesn't exist + local vfs = mp.get_property_native("vf") + + for i,vf in pairs(vfs) do + if vf["label"] == label then + table.remove(vfs, i) + mp.set_property_native("vf", vfs) + return true + end + end + return false +end + +local function add_vf(label, filter) + return mp.command(('vf add @%s:%s'):format(label, filter)) +end + +function start_detect() + -- exit if detection is already in progress + if timer then + mp.msg.warn("already detecting!") + return + end + + mp.set_property("deinterlace","no") + del_filter_if_present(pullup_label) + del_filter_if_present(dominance_label) + + -- insert the detection filters + if not (add_vf(detect_label, 'idet') and + add_vf(dominance_label, 'setfield=mode=auto') and + add_vf(pullup_label, 'lavfi-pullup') and + add_vf(ivtc_detect_label, 'idet')) then + mp.msg.error("failed to insert detection filters") + return + end + + -- wait to gather data + timer = mp.add_timeout(detect_seconds, select_filter) +end + +function stop_detect() + del_filter_if_present(detect_label) + del_filter_if_present(ivtc_detect_label) + timer = nil +end + +progressive, interlaced_tff, interlaced_bff, interlaced = 0, 1, 2, 3, 4 + +function judge(label) + -- get the metadata + local result = mp.get_property_native(string.format("vf-metadata/%s", label)) + local num_tff = tonumber(result["lavfi.idet.multiple.tff"]) + local num_bff = tonumber(result["lavfi.idet.multiple.bff"]) + local num_progressive = tonumber(result["lavfi.idet.multiple.progressive"]) + local num_undetermined = tonumber(result["lavfi.idet.multiple.undetermined"]) + local num_interlaced = num_tff + num_bff + local num_determined = num_interlaced + num_progressive + + mp.msg.verbose(label.." progressive = "..num_progressive) + mp.msg.verbose(label.." interlaced-tff = "..num_tff) + mp.msg.verbose(label.." interlaced-bff = "..num_bff) + mp.msg.verbose(label.." undetermined = "..num_undetermined) + + if num_determined < num_undetermined then + mp.msg.warn("majority undetermined frames") + end + if num_progressive > 20*num_interlaced then + return progressive + elseif num_tff > 10*num_bff then + return interlaced_tff + elseif num_bff > 10*num_tff then + return interlaced_bff + else + return interlaced + end +end + +function select_filter() + -- handle the first detection filter results + local verdict = judge(detect_label) + local ivtc_verdict = judge(ivtc_detect_label) + local dominance = "auto" + if verdict == progressive then + mp.msg.info("progressive: doing nothing") + stop_detect() + del_filter_if_present(dominance_label) + del_filter_if_present(pullup_label) + return + else + if verdict == interlaced_tff then + dominance = "tff" + add_vf(dominance_label, 'setfield=mode='..dominance) + elseif verdict == interlaced_bff then + dominance = "bff" + add_vf(dominance_label, 'setfield=mode='..dominance) + else + del_filter_if_present(dominance_label) + end + end + + -- handle the ivtc detection filter results + if ivtc_verdict == progressive then + mp.msg.info(string.format("telecined with %s field dominance: using pullup", dominance)) + stop_detect() + else + mp.msg.info(string.format("interlaced with %s field dominance: setting deinterlace property", dominance)) + del_filter_if_present(pullup_label) + mp.set_property("deinterlace","yes") + stop_detect() + end +end + +mp.add_key_binding("ctrl+d", script_name, start_detect) |