forked from ParadoxSpiral/mpv-clip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
clip.lua
224 lines (195 loc) · 7.05 KB
/
clip.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
-- Copyright (C) 2017 ParadoxSpiral
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with Parabot. If not, see <http://www.gnu.org/licenses/>.
-- Encode a clip of the current file
local mp = require 'mp'
local options = require 'mp.options'
require 'os'
-- Options
local o = {
-- Key bindings
key_set_start_frame = "c",
key_set_stop_frame = "C",
key_start_lossless = "ctrl+C",
key_start_encode = "ctrl+E",
key_start_gif = "ctrl+G",
-- Audio settings
audio_codec = "libopus",
audio_bitrate = "192k",
-- Video settings (encode)
video_codec = "libx265",
video_crf = "25",
video_pixel_format = "yuv420p10",
video_width = "", -- source width if not specified
video_height= "", -- source height if not specified
video_upscale = false, -- upscale if video res is lower than desired res
video_container = "mkv",
-- Video settings (gif)
gif_fps = "14",
gif_scale = "480x270",
gif_optimize = true,
-- Misc settings
encoding_preset = "medium", -- empty for no preset
output_directory = "clip",
clear_start_stop_on_encode = false,
block_exit = true, -- stop mpv from quitting before the encode finished, if false…
-- …mpv will quit but ffmpeg will be kept alive
}
options.read_options(o)
-- Global mutable variables
local start_frame = nil
local stop_frame = nil
local clip_type = 0 -- 0->lossless, 1->x265, 2->gif
function encode()
if not start_frame then
mp.osd_message("No start frame set!")
return
end
if not stop_frame then
mp.osd_message("No stop frame set!")
return
end
if start_frame == stop_frame then
mp.osd_message("Cannot create zero length clip!", 1.5)
end
local path = mp.get_property("path")
local filename = mp.get_property("filename")
local fileExt = filename:match("^.+%.(.+)$")
local currentDir = string.sub(path, 1, string.len(path)-string.len(filename))
local out = currentDir..o.output_directory.."/"..mp.get_property("media-title").."-clip-"..start_frame..
"-"..stop_frame
local width = mp.get_property("width")
local height = mp.get_property("height")
if o.video_width ~= "" and (o.video_width < width or o.video_upscale) then
width = o.video_width
end
if o.video_height ~= "" and (o.video_height < height or o.video_upscale) then
height = o.video_height
end
local saf = start_frame
local sof = stop_frame
if o.clear_start_stop_on_encode then
start_frame = nil
stop_fram = nil
end
local preset = ""
if o.encoding_preset ~= "" then
preset = "-preset "..o.encoding_preset
end
-- Check if ytdl is needed
local input
if not os.execute('ffprobe "'..path..'"') then
input = '/usr/local/bin/youtube-dl "'..path..'" -o - | ffmpeg -ss '..saf..' -i -'
else
if clip_type == 2 then
input = '/usr/local/bin/ffmpeg -ss '..saf..' -t '..sof-saf..' -i "'..path..'"'
else
input = '/usr/local/bin/ffmpeg -ss '..saf..' -i "'..path..'"'
end
end
-- FIXME: Map metadata properly, like chapters or embedded fonts
local command = input
local precommand = input
--local endcommand = "/usr/local/bin/imageoptim \""..out..".gif\""
--local endcommand = "/usr/local/bin/imageoptim "..'"'..out..".gif"..'"'
--local endcommand = "/usr/local/bin/imageoptim '"..currentDir..o.output_directory.."/*.gif'" -- all gif image
--local endcommand = "/usr/local/bin/gifsicle -O2 -o "..'"'..out..'" "'..out..'"'
if clip_type == 0 then
command = command.." -t "..sof-saf.." -c:v copy -c:a copy"..' "'..out.."."..fileExt..'"'
elseif clip_type == 1 then
command = command.." -t "..sof-saf.." -c:a "..o.audio_codec.." -b:a "..o.audio_bitrate.." -c:v "..o.video_codec..
" -pix_fmt "..o.video_pixel_format.." -crf "..o.video_crf.." -s "..width.."x"..
height.." "..preset..' "'..out.."."..o.video_container..'"'
elseif clip_type == 2 then
local baseOpt = "fps="..o.gif_fps..",scale="..o.gif_scale
precommand = command.." -vf \""..baseOpt..":flags=lanczos,palettegen\" -y /tmp/palette.png"
command = command.." -i /tmp/palette.png -lavfi \""..baseOpt..":flags=lanczos [x]; [x][1:v] paletteuse\""..' "'..out..".gif"..'"'
--os.execute("echo "..precommand.." | pbcopy")
--os.execute("echo "..command.." | pbcopy")
--os.execute("echo "..endcommand.." | pbcopy")
end
local time = os.time()
startMsg = "Starting encode from "..saf.." to "..sof
os.execute("osascript -e 'display notification \""..startMsg.."\" with title \"mpv\"'")
mp.osd_message(startMsg, 3.5)
if o.block_exit then
--endMsg = "in $(expr \\( `date +%s` \\) - "..time..") seconds"
if clip_type == 2 then
os.execute(precommand)
os.execute(command)
--os.execute(endcommand)
os.execute("osascript -e 'display notification \"End\" with title \"mpv\" sound name \"glass\"'")
else
os.execute(command.." && osascript -e 'display notification \"End\" with title \"mpv\" sound name \"glass\"'")
end
--os.execute(command)
--mp.osd_message("Finished encode of "..out.." in "..os.time()-time.." seconds", 3.5)
--endMsg = "Finished encode from "..saf.." to "..sof.." in "..os.time()-time.." seconds"
--os.execute("osascript -e 'display notification \""..endMsg.."\" with title \"mpv\" sound name \"glass\"'")
--mp.osd_message(endMsg, 3.5)
else
-- FIXME: Won't work on Windows, because of special snowflake pipe naming
local ipc = mp.get_property("input-ipc-server")
local del_tmp = ""
if ipc == "" then
ipc = os.tmpname()
mp.set_property("input-ipc-server", ipc)
del_tmp = " && lua -e 'os.remove(\""..ipc.."\")'"
end
os.execute(command..' && echo "{ \\"command\\": [\\"show-text\\", \\"Finished encode of \''
..out..'\' in $(lua -e "print(os.time()-'..time..')") seconds\\", 3500] }" | socat - '
..ipc..del_tmp.." &")
end
end
-- Start frame key binding
mp.add_key_binding(o.key_set_start_frame, "clip-start",
function()
start_frame = mp.get_property("playback-time")
if not start_frame then
start_frame = 0
end
mp.osd_message("Clip start at "..start_frame.."s")
end)
-- Stop frame key binding
mp.add_key_binding(o.key_set_stop_frame, "clip-end",
function()
stop_frame = mp.get_property("playback-time")
if not stop_frame then
mp.osd_message("playback-time is nil! (file not yet loaded?)")
else
mp.osd_message("Clip end at "..stop_frame.."s")
end
end)
-- Start encode key binding
mp.add_key_binding(o.key_start_lossless, "clip-lossless",
function()
clip_type = 0
encode()
end)
mp.add_key_binding(o.key_start_encode, "clip-encode",
function()
clip_type = 1
encode()
end)
mp.add_key_binding(o.key_start_gif, "clip-gif",
function()
clip_type = 2
encode()
end)
-- Reset start/stop frame when a new file is loaded
mp.register_event("start-file",
function()
start_frame = nil
stop_frame = nil
end)