145 lines
4.1 KiB
Lua
145 lines
4.1 KiB
Lua
local msg = require "mp.msg"
|
|
local utils = require "mp.utils"
|
|
local options = require "mp.options"
|
|
|
|
local cut_pos = nil
|
|
local copy_audio = true
|
|
local o = {
|
|
target_dir = "~",
|
|
vcodec = "rawvideo",
|
|
acodec = "pcm_s16le",
|
|
prevf = "",
|
|
vf = "format=yuv444p16$hqvf,scale=in_color_matrix=$matrix,format=bgr24",
|
|
hqvf = "",
|
|
postvf = "",
|
|
opts = "",
|
|
ext = "avi",
|
|
command_template = [[
|
|
ffmpeg -v warning -y -stats
|
|
-ss $shift -i "$in" -t $duration
|
|
-c:v $vcodec -c:a $acodec $audio
|
|
-vf $prevf$vf$postvf $opts "$out.$ext"
|
|
]],
|
|
}
|
|
options.read_options(o)
|
|
|
|
function timestamp(duration)
|
|
local hours = duration / 3600
|
|
local minutes = duration % 3600 / 60
|
|
local seconds = duration % 60
|
|
return string.format("%02d:%02d:%02.03f", hours, minutes, seconds)
|
|
end
|
|
|
|
function osd(str)
|
|
return mp.osd_message(str, 3)
|
|
end
|
|
|
|
function get_homedir()
|
|
-- It would be better to do platform detection instead of fallback but
|
|
-- it's not that easy in Lua.
|
|
return os.getenv("HOME") or os.getenv("USERPROFILE") or ""
|
|
end
|
|
|
|
function log(str)
|
|
local logpath = utils.join_path(
|
|
o.target_dir:gsub("~", get_homedir()),
|
|
"mpv_slicing.log")
|
|
f = io.open(logpath, "a")
|
|
f:write(string.format("# %s\n%s\n",
|
|
os.date("%Y-%m-%d %H:%M:%S"),
|
|
str))
|
|
f:close()
|
|
end
|
|
|
|
function escape(str)
|
|
-- FIXME(Kagami): This escaping is NOT enough, see e.g.
|
|
-- https://stackoverflow.com/a/31413730
|
|
-- Consider using `utils.subprocess` instead.
|
|
return str:gsub("\\", "\\\\"):gsub('"', '\\"')
|
|
end
|
|
|
|
function trim(str)
|
|
return str:gsub("^%s+", ""):gsub("%s+$", "")
|
|
end
|
|
|
|
function get_csp()
|
|
local csp = mp.get_property("colormatrix")
|
|
if csp == "bt.601" then return "bt601"
|
|
elseif csp == "bt.709" then return "bt709"
|
|
elseif csp == "smpte-240m" then return "smpte240m"
|
|
else
|
|
local err = "Unknown colorspace: " .. csp
|
|
osd(err)
|
|
error(err)
|
|
end
|
|
end
|
|
|
|
function get_outname(shift, endpos)
|
|
local name = mp.get_property("filename")
|
|
local dotidx = name:reverse():find(".", 1, true)
|
|
if dotidx then name = name:sub(1, -dotidx-1) end
|
|
name = name:gsub(" ", "_")
|
|
name = name:gsub(":", "-")
|
|
name = name .. string.format(".%s-%s", timestamp(shift), timestamp(endpos))
|
|
return name
|
|
end
|
|
|
|
function cut(shift, endpos)
|
|
local cmd = trim(o.command_template:gsub("%s+", " "))
|
|
local inpath = escape(utils.join_path(
|
|
utils.getcwd(),
|
|
mp.get_property("stream-path")))
|
|
local outpath = escape(utils.join_path(
|
|
o.target_dir:gsub("~", get_homedir()),
|
|
get_outname(shift, endpos)))
|
|
|
|
cmd = cmd:gsub("$shift", shift)
|
|
cmd = cmd:gsub("$duration", endpos - shift)
|
|
cmd = cmd:gsub("$vcodec", o.vcodec)
|
|
cmd = cmd:gsub("$acodec", o.acodec)
|
|
cmd = cmd:gsub("$audio", copy_audio and "" or "-an")
|
|
cmd = cmd:gsub("$prevf", o.prevf)
|
|
cmd = cmd:gsub("$vf", o.vf)
|
|
cmd = cmd:gsub("$hqvf", o.hqvf)
|
|
cmd = cmd:gsub("$postvf", o.postvf)
|
|
cmd = cmd:gsub("$matrix", get_csp())
|
|
cmd = cmd:gsub("$opts", o.opts)
|
|
-- Beware that input/out filename may contain replacing patterns.
|
|
cmd = cmd:gsub("$ext", o.ext)
|
|
cmd = cmd:gsub("$out", outpath)
|
|
cmd = cmd:gsub("$in", inpath, 1)
|
|
|
|
msg.info(cmd)
|
|
log(cmd)
|
|
os.execute(cmd)
|
|
end
|
|
|
|
function toggle_mark()
|
|
local pos = mp.get_property_number("time-pos")
|
|
if cut_pos then
|
|
local shift, endpos = cut_pos, pos
|
|
if shift > endpos then
|
|
shift, endpos = endpos, shift
|
|
end
|
|
if shift == endpos then
|
|
osd("Cut fragment is empty")
|
|
else
|
|
cut_pos = nil
|
|
osd(string.format("Cut fragment: %s - %s",
|
|
timestamp(shift),
|
|
timestamp(endpos)))
|
|
cut(shift, endpos)
|
|
end
|
|
else
|
|
cut_pos = pos
|
|
osd(string.format("Marked %s as start position", timestamp(pos)))
|
|
end
|
|
end
|
|
|
|
function toggle_audio()
|
|
copy_audio = not copy_audio
|
|
osd("Audio capturing is " .. (copy_audio and "enabled" or "disabled"))
|
|
end
|
|
|
|
mp.add_key_binding("c", "slicing_mark", toggle_mark)
|
|
mp.add_key_binding("a", "slicing_audio", toggle_audio)
|