summaryrefslogtreecommitdiff
path: root/mpv/scripts/autodeint.lua
diff options
context:
space:
mode:
Diffstat (limited to 'mpv/scripts/autodeint.lua')
-rw-r--r--mpv/scripts/autodeint.lua158
1 files changed, 158 insertions, 0 deletions
diff --git a/mpv/scripts/autodeint.lua b/mpv/scripts/autodeint.lua
new file mode 100644
index 0000000..16f56ea
--- /dev/null
+++ b/mpv/scripts/autodeint.lua
@@ -0,0 +1,158 @@
+-- From: https://github.com/mpv-player/mpv/tree/master/TOOLS/lua
+-- (with slight modifications)
+--
+-- 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=lavfi=idet,pullup,vf=lavfi=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 mpv's ``field-dominance`` property.
+--
+-- 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
+--
+-- This script requires a recent version of ffmpeg for which the idet
+-- filter adds the required metadata.
+
+require "mp.msg"
+
+script_name = mp.get_script_name()
+detect_label = string.format("%s-detect", script_name)
+pullup_label = string.format("%s", 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
+
+function start_detect()
+ -- exit if detection is already in progress
+ if timer then
+ mp.msg.warn("already detecting!")
+ mp.osd_message("autodeint: already detecting!")
+ return
+ end
+
+ mp.set_property("deinterlace","no")
+ del_filter_if_present(pullup_label)
+
+ -- insert the detection filter
+ local cmd = string.format('vf add @%s:lavfi=graph="idet",@%s:pullup,@%s:lavfi=graph="idet"',
+ detect_label, pullup_label, ivtc_detect_label)
+ if not mp.command(cmd) then
+ mp.msg.error("failed to insert detection filters")
+ mp.osd_message("autodeint: failed to insert detection filters")
+ return
+ end
+
+ -- wait to gather data
+ mp.osd_message("autodeint: starting detection")
+ 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))
+ -- filter might have been removed by third party
+ if not result or next(result) == nil then
+ return progressive
+ end
+ num_tff = tonumber(result["lavfi.idet.multiple.tff"])
+ num_bff = tonumber(result["lavfi.idet.multiple.bff"])
+ num_progressive = tonumber(result["lavfi.idet.multiple.progressive"])
+ num_undetermined = tonumber(result["lavfi.idet.multiple.undetermined"])
+ num_interlaced = num_tff + num_bff
+ 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
+ verdict = judge(detect_label)
+ if verdict == progressive then
+ mp.msg.info("progressive: doing nothing")
+ mp.osd_message("autodeint: no deinterlacing required")
+ stop_detect()
+ return
+ elseif verdict == interlaced_tff then
+ mp.set_property("field-dominance", "top")
+ elseif verdict == interlaced_bff then
+ mp.set_property("field-dominance", "bottom")
+ elseif verdict == interlaced then
+ mp.set_property("field-dominance", "auto")
+ end
+
+ -- handle the ivtc detection filter results
+ verdict = judge(ivtc_detect_label)
+ if verdict == progressive then
+ mp.msg.info(string.format("telecinied with %s field dominance: using pullup", mp.get_property("field-dominance")))
+ mp.osd_message("autodeint: using pullup")
+ stop_detect()
+ else
+ mp.msg.info(string.format("interlaced with %s field dominance: setting deinterlace property", mp.get_property("field-dominance")))
+ del_filter_if_present(pullup_label)
+ mp.osd_message(string.format("autodeint: setting deinterlace property (%s)", mp.get_property("field-dominance")))
+ mp.set_property("deinterlace", "yes")
+ stop_detect()
+ end
+end
+
+mp.add_key_binding("ctrl+d", script_name, start_detect)