summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TOOLS/lua/autodeint.lua164
1 files changed, 164 insertions, 0 deletions
diff --git a/TOOLS/lua/autodeint.lua b/TOOLS/lua/autodeint.lua
new file mode 100644
index 0000000000..d834f96a91
--- /dev/null
+++ b/TOOLS/lua/autodeint.lua
@@ -0,0 +1,164 @@
+-- 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 filter vf=lavfi=idet. After 4 second, it examines the results
+-- to determine whether the content progressive or interlaced and the
+-- interlacing field dominance. It immediately sets the latter within
+-- mpv.
+--
+-- If the content is judged not to be progressive, it may be either
+-- interlaced or telecined. To determine which one, the video is
+-- seeked back to the detection starting point with the "pullup"
+-- filter inserted. After another four seconds, if idet thinks that
+-- the pulled up viedo is "progressive", then pullup is the correct
+-- filter and this script leaves it in places while removing the idet
+-- filter. Otherwise, the content plain interlaced and mpv's deinterlace
+-- property is set. This will usually insert the yadif deinterlacing filter.
+--
+-- The default detection time may be overridden by adding
+--
+-- --lua-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)
+
+-- 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!")
+ return
+ end
+
+ mp.set_property("deinterlace","no")
+ del_filter_if_present(pullup_label)
+
+ percent_pos = mp.get_property("percent-pos")
+
+ -- insert the detection filter
+ local cmd = string.format('vf add @%s:lavfi=graph="idet"', detect_label)
+ if not mp.command(cmd) then
+ mp.msg.error("failed to insert detection filter")
+ return
+ end
+
+ -- wait to gather data
+ timer = mp.add_timeout(detect_seconds, judge_field_dominance)
+end
+
+function stop_detect()
+ del_filter_if_present(detect_label)
+ timer = nil
+ mp.set_property("playback-pos", percent_pos)
+end
+
+progressive, interlaced_tff, interlaced_bff, interlaced = 0, 1, 2, 3, 4
+
+function judge()
+ -- get the metadata
+ local result = mp.get_property_native(string.format("vf-metadata/%s", detect_label))
+ 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("progressive = "..num_progressive)
+ mp.msg.verbose("interlaced-tff = "..num_tff)
+ mp.msg.verbose("interlaced-bff = "..num_bff)
+ mp.msg.verbose("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 judge_field_dominance()
+ verdict = judge()
+ if verdict == progressive then
+ stop_detect()
+ mp.msg.info("progressive: doing nothing")
+ 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
+
+ local cmd = string.format("vf pre @%s:pullup", pullup_label)
+ if not mp.command(cmd) then
+ mp.msg.error("failed to insert pullup filter")
+ stop_detect()
+ return
+ end
+
+ -- redo the detection with the pullup filter to see if it's telecined
+ mp.set_property("percent-pos", percent_pos)
+ timer = mp.add_timeout(detect_seconds, judge_ivtc)
+end
+
+function judge_ivtc()
+ verdict = judge()
+
+ if verdict == progressive then
+ mp.msg.info(string.format("telecinied with %s field dominance: using pullup", mp.get_property("field-dominance")))
+ 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.set_property("deinterlace","yes")
+ stop_detect()
+ end
+
+ return
+end
+
+mp.add_key_binding("ctrl+d", script_name, start_detect)