summaryrefslogtreecommitdiffstats
path: root/TOOLS/lua/autocrop.lua
diff options
context:
space:
mode:
Diffstat (limited to 'TOOLS/lua/autocrop.lua')
-rw-r--r--TOOLS/lua/autocrop.lua246
1 files changed, 111 insertions, 135 deletions
diff --git a/TOOLS/lua/autocrop.lua b/TOOLS/lua/autocrop.lua
index af6021b75a..ea57d15658 100644
--- a/TOOLS/lua/autocrop.lua
+++ b/TOOLS/lua/autocrop.lua
@@ -1,96 +1,69 @@
--[[
-This script uses the lavfi cropdetect filter to automatically
-insert a crop filter with appropriate parameters for the
-currently playing video.
-
-It will automatically crop the video, when playback starts.
-
-Also It registers the key-binding "C" (shift+c). You can manually
-crop the video by pressing the "C" (shift+c) key.
-
-If the "C" key is pressed again, the crop filter is removed
-restoring playback to its original state.
-
-The workflow is as follows: First, it inserts the filter
-vf=lavfi=cropdetect. After <detect_seconds> (default is 1)
-seconds, it then inserts the filter vf=crop=w:h:x:y, where
-w,h,x,y are determined from the vf-metadata gathered by
-cropdetect. The cropdetect filter is removed immediately after
-the crop filter is inserted as it is no longer needed.
-
-Since the crop parameters are determined from the 1 second of
-video between inserting the cropdetect and crop filters, the "C"
-key should be pressed at a position in the video where the crop
-region is unambiguous (i.e., not a black frame, black background
-title card, or dark scene).
-
-The default options can be overridden by adding
-script-opts-append=autocrop-<parameter>=<value> into mpv.conf
-
-List of available parameters (For default values, see <options>):
-
-auto: bool - Whether to automatically apply crop at the start of
- playback. If you don't want to crop automatically, set it to
- false or add "script-opts-append=autocrop-auto=no" into
- mpv.conf.
-
-auto_delay: seconds - Delay before starting crop in auto mode.
- You can try to increase this value to avoid dark scene or
- fade in at beginning. Automatic cropping will not occur if
- the value is larger than the remaining playback time.
-
-detect_limit: number[0-255] - Black threshold for cropdetect.
- Smaller values will generally result in less cropping.
- See limit of https://ffmpeg.org/ffmpeg-filters.html#cropdetect
-
-detect_round: number[2^n] - The value which the width/height
- should be divisible by. Smaller values ​​have better detection
- accuracy. If you have problems with other filters,
- you can try to set it to 4 or 16.
- See round of https://ffmpeg.org/ffmpeg-filters.html#cropdetect
-
-detect_min_ratio: number[0.0-1.0] - The ratio of the minimum clip
- size to the original. If the picture is over cropped or under
- cropped, try adjusting this value.
-
-detect_seconds: seconds - How long to gather cropdetect data.
- Increasing this may be desirable to allow cropdetect more
- time to collect data.
---]]
+This script uses the lavfi cropdetect filter and the video-crop property to
+automatically crop the currently playing video with appropriate parameters.
+
+It automatically crops the video when playback starts.
+
+You can also manually crop the video by pressing the "C" (shift+c) key.
+Pressing it again undoes the crop.
-require "mp.msg"
-require 'mp.options'
+The workflow is as follows: First, it inserts the cropdetect filter. After
+<detect_seconds> (default is 1) seconds, it then sets video-crop based on the
+vf-metadata values gathered by cropdetect. The cropdetect filter is removed
+after video-crop is set as it is no longer needed.
+Since the crop parameters are determined from the 1 second of video between
+inserting the cropdetect filter and setting video-crop, the "C" key should be
+pressed at a position in the video where the crop region is unambiguous (i.e.,
+not a black frame, black background title card, or dark scene).
+
+If non-copy-back hardware decoding is in use, hwdec is temporarily disabled for
+the duration of cropdetect as the filter would fail otherwise.
+
+These are the default options. They can be overridden by adding
+script-opts-append=autocrop-<parameter>=<value> to mpv.conf.
+--]]
local options = {
+ -- Whether to automatically apply crop at the start of playback. If you
+ -- don't want to crop automatically, add
+ -- script-opts-append=autocrop-auto=no to mpv.conf.
auto = true,
+ -- Delay before starting crop in auto mode. You can try to increase this
+ -- value to avoid dark scenes or fade ins at beginning. Automatic cropping
+ -- will not occur if the value is larger than the remaining playback time.
auto_delay = 4,
+ -- Black threshold for cropdetect. Smaller values will generally result in
+ -- less cropping. See limit of
+ -- https://ffmpeg.org/ffmpeg-filters.html#cropdetect
detect_limit = "24/255",
+ -- The value which the width/height should be divisible by. Smaller
+ -- values have better detection accuracy. If you have problems with
+ -- other filters, you can try to set it to 4 or 16. See round of
+ -- https://ffmpeg.org/ffmpeg-filters.html#cropdetect
detect_round = 2,
+ -- The ratio of the minimum clip size to the original. A number from 0 to
+ -- 1. If the picture is over cropped, try adjusting this value.
detect_min_ratio = 0.5,
- detect_seconds = 1
+ -- How long to gather cropdetect data. Increasing this may be desirable to
+ -- allow cropdetect more time to collect data.
+ detect_seconds = 1,
+ -- Whether the OSD shouldn't be used when cropdetect and video-crop are
+ -- applied and removed.
+ suppress_osd = false,
}
-read_options(options)
-local label_prefix = mp.get_script_name()
-local labels = {
- crop = string.format("%s-crop", label_prefix),
- cropdetect = string.format("%s-cropdetect", label_prefix)
-}
+require "mp.options".read_options(options)
+
+local cropdetect_label = mp.get_script_name() .. "-cropdetect"
timers = {
auto_delay = nil,
detect_crop = nil
}
-function is_filter_present(label)
- local filters = mp.get_property_native("vf")
- for index, filter in pairs(filters) do
- if filter["label"] == label then
- return true
- end
- end
- return false
-end
+local hwdec_backup
+
+local command_prefix = options.suppress_osd and 'no-osd' or ''
function is_enough_time(seconds)
@@ -101,53 +74,64 @@ function is_enough_time(seconds)
return playtime_remaining and time_needed < playtime_remaining
end
-function is_cropable()
- local vid = mp.get_property_native("vid")
- local is_album = vid and mp.get_property_native(
- string.format("track-list/%d/albumart", vid)
- ) or false
+function is_cropable(time_needed)
+ if mp.get_property_native('current-tracks/video/image') ~= false then
+ mp.msg.warn("autocrop only works for videos.")
+ return false
+ end
+
+ if not is_enough_time(time_needed) then
+ mp.msg.warn("Not enough time to detect crop.")
+ return false
+ end
- return vid and not is_album
+ return true
end
-function remove_filter(label)
- if is_filter_present(label) then
- mp.command(string.format('vf remove @%s', label))
- return true
+function remove_cropdetect()
+ for _, filter in pairs(mp.get_property_native("vf")) do
+ if filter.label == cropdetect_label then
+ mp.command(
+ string.format("%s vf remove @%s", command_prefix, filter.label))
+
+ return
+ end
end
- return false
end
-function cleanup()
-
- -- Remove all existing filters.
- for key, value in pairs(labels) do
- remove_filter(value)
+function restore_hwdec()
+ if hwdec_backup then
+ mp.set_property("hwdec", hwdec_backup)
+ hwdec_backup = nil
end
+end
+
+function cleanup()
+ remove_cropdetect()
-- Kill all timers.
for index, timer in pairs(timers) do
if timer then
timer:kill()
- timer = nil
+ timers[index] = nil
end
end
+
+ restore_hwdec()
end
function detect_crop()
+ local time_needed = options.detect_seconds
- -- If it's not cropable, exit.
- if not is_cropable() then
- mp.msg.warn("autocrop only works for videos.")
+ if not is_cropable(time_needed) then
return
end
- -- Verify if there is enough time to detect crop.
- local time_needed = options.detect_seconds
-
- if not is_enough_time(time_needed) then
- mp.msg.warn("Not enough time to detect crop.")
- return
+ local hwdec_current = mp.get_property("hwdec-current")
+ if hwdec_current:find("-copy$") == nil and hwdec_current ~= "no" and
+ hwdec_current ~= "crystalhd" and hwdec_current ~= "rkmpp" then
+ hwdec_backup = mp.get_property("hwdec")
+ mp.set_property("hwdec", "no")
end
-- Insert the cropdetect filter.
@@ -156,8 +140,8 @@ function detect_crop()
mp.command(
string.format(
- 'vf pre @%s:cropdetect=limit=%s:round=%d:reset=0',
- labels.cropdetect, limit, round
+ '%s vf pre @%s:cropdetect=limit=%s:round=%d:reset=0',
+ command_prefix, cropdetect_label, limit, round
)
)
@@ -168,13 +152,9 @@ end
function detect_end()
-- Get the metadata and remove the cropdetect filter.
- local cropdetect_metadata =
- mp.get_property_native(
- string.format("vf-metadata/%s",
- labels.cropdetect
- )
- )
- remove_filter(labels.cropdetect)
+ local cropdetect_metadata = mp.get_property_native(
+ "vf-metadata/" .. cropdetect_label)
+ remove_cropdetect()
-- Remove the timer of detect crop.
if timers.detect_crop then
@@ -182,6 +162,8 @@ function detect_end()
timers.detect_crop = nil
end
+ restore_hwdec()
+
local meta = {}
-- Verify the existence of metadata.
@@ -195,7 +177,7 @@ function detect_end()
else
mp.msg.error("No crop data.")
mp.msg.info("Was the cropdetect filter successfully inserted?")
- mp.msg.info("Does your version of ffmpeg/libav support AVFrame metadata?")
+ mp.msg.info("Does your version of FFmpeg support AVFrame metadata?")
return
end
@@ -217,7 +199,6 @@ function detect_end()
else
mp.msg.error("Got empty crop data.")
mp.msg.info("You might need to increase detect_seconds.")
- return
end
apply_crop(meta)
@@ -226,32 +207,27 @@ end
function apply_crop(meta)
-- Verify if it is necessary to crop.
- local is_effective = meta.x > 0 or meta.y > 0
- or meta.w < meta.max_w or meta.h < meta.max_h
-
- if not is_effective then
- mp.msg.info("No area detected for cropping.")
- return
- end
+ local is_effective = meta.w and meta.h and meta.x and meta.y and
+ (meta.x > 0 or meta.y > 0
+ or meta.w < meta.max_w or meta.h < meta.max_h)
-- Verify it is not over cropped.
- local is_excessive = meta.w < meta.min_w and meta.h < meta.min_h
-
- if is_excessive then
+ local is_excessive = false
+ if is_effective and (meta.w < meta.min_w or meta.h < meta.min_h) then
mp.msg.info("The area to be cropped is too large.")
mp.msg.info("You might need to decrease detect_min_ratio.")
- return
+ is_excessive = true
end
- -- Remove existing crop.
- remove_filter(labels.crop)
+ if not is_effective or is_excessive then
+ -- Clear any existing crop.
+ mp.command(string.format("%s set file-local-options/video-crop ''", command_prefix))
+ return
+ end
-- Apply crop.
- mp.command(
- string.format("vf pre @%s:lavfi-crop=w=%s:h=%s:x=%s:y=%s",
- labels.crop, meta.w, meta.h, meta.x, meta.y
- )
- )
+ mp.command(string.format("%s set file-local-options/video-crop %sx%s+%s+%s",
+ command_prefix, meta.w, meta.h, meta.x, meta.y))
end
function on_start()
@@ -275,8 +251,7 @@ function on_start()
-- Verify if there is enough time for autocrop.
local time_needed = options.auto_delay + options.detect_seconds
- if not is_enough_time(time_needed) then
- mp.msg.warn("Not enough time for autocrop.")
+ if not is_cropable(time_needed) then
return
end
@@ -303,7 +278,8 @@ function on_toggle()
end
-- Cropped => Remove it.
- if remove_filter(labels.crop) then
+ if mp.get_property("video-crop") ~= "" then
+ mp.command(string.format("%s set file-local-options/video-crop ''", command_prefix))
return
end
@@ -313,7 +289,7 @@ function on_toggle()
return
end
- -- Neither => Do delectcrop.
+ -- Neither => Detect crop.
detect_crop()
end