-
Notifications
You must be signed in to change notification settings - Fork 12
/
mpv-gif.lua
190 lines (144 loc) · 5.29 KB
/
mpv-gif.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
-- Original by Ruin0x11
-- Ported to Windows by Scheliux, Dragoner7
-- Create animated GIFs with mpv
-- Requires ffmpeg.
-- Adapted from http://blog.pkh.me/p/21-high-quality-gif-with-ffmpeg.html
-- Usage: "g" to set start frame, "G" to set end frame, "Ctrl+g" to create.
require 'mp.options'
local msg = require 'mp.msg'
local options = {
dir = "C:/Program Files/mpv/gifs",
rez = 600,
fps = 15,
}
read_options(options, "gif")
local fps
-- Check for invalid fps values
-- Can you believe Lua doesn't have a proper ternary operator in the year of our lord 2020?
if options.fps ~= nil and options.fps >= 1 and options.fps < 30 then
fps = options.fps
else
fps = 15
end
-- Set this to the filters to pass into ffmpeg's -vf option.
-- filters="fps=24,scale=320:-1:flags=spline"
filters=string.format("fps=%s,scale='trunc(ih*dar/2)*2:trunc(ih/2)*2',setsar=1/1,scale=%s:-1:flags=spline", fps, options.rez) --change spline to lanczos depending on preference
-- Setup output directory
output_directory=string.gsub(options.dir, '\"', '')
start_time = -1
end_time = -1
palette="%TEMP%palette.png"
-- The roundabout way has to be used due to a some weird
-- behavior with %TEMP% on the subtitles= parameter in ffmpeg
-- on Windows–it needs to be quadruple backslashed
subs = "C:/Users/%USERNAME%/AppData/Local/Temp/subs.srt"
function make_gif_with_subtitles()
make_gif_internal(true)
end
function make_gif()
make_gif_internal(false)
end
function table_length(t)
local count = 0
for _ in pairs(t) do count = count + 1 end
return count
end
function make_gif_internal(burn_subtitles)
local start_time_l = start_time
local end_time_l = end_time
if start_time_l == -1 or end_time_l == -1 or start_time_l >= end_time_l then
mp.osd_message("Invalid start/end time.")
return
end
mp.osd_message("Creating GIF.")
-- shell escape
function esc(s)
return string.gsub(s, '"', '"\\""')
end
function esc_for_sub(s)
s = string.gsub(s, [[\]], [[/]])
s = string.gsub(s, '"', '"\\""')
s = string.gsub(s, ":", [[\\:]])
s = string.gsub(s, "'", [[\\']])
return s
end
local pathname = mp.get_property("path", "")
local trim_filters = esc(filters)
local position = start_time_l
local duration = end_time_l - start_time_l
if burn_subtitles then
-- Determine currently active sub track
local i = 0
local tracks_count = mp.get_property_number("track-list/count")
local subs_array = {}
-- check for subtitle tracks
while i < tracks_count do
local type = mp.get_property(string.format("track-list/%d/type", i))
local selected = mp.get_property(string.format("track-list/%d/selected", i))
-- if it's a sub track, save it
if type == "sub" then
local length = table_length(subs_array)
subs_array[length] = selected == "yes"
end
i = i + 1
end
if table_length(subs_array) > 0 then
local correct_track = 0
-- iterate through saved subtitle tracks until the correct one is found
for index, is_selected in pairs(subs_array) do
if (is_selected) then
correct_track = index
end
end
trim_filters = trim_filters .. string.format(",subtitles=%s:si=%s", esc_for_sub(pathname), correct_track)
end
end
-- first, create the palette
args = string.format('ffmpeg -v warning -ss %s -t %s -i "%s" -vf "%s,palettegen" -y "%s"', position, duration, esc(pathname), esc(trim_filters), esc(palette))
msg.debug(args)
os.execute(args)
-- then, make the gif
local filename = mp.get_property("filename/no-ext")
local file_path = output_directory .. "/" .. filename
-- increment filename
for i=0,999 do
local fn = string.format('%s_%03d.gif',file_path,i)
if not file_exists(fn) then
gifname = fn
break
end
end
if not gifname then
mp.osd_message('No available filenames!')
return
end
local copyts = ""
if burn_subtitles then
copyts = "-copyts"
end
args = string.format('ffmpeg -v warning -ss %s %s -t %s -i "%s" -i "%s" -lavfi "%s [x]; [x][1:v] paletteuse" -y "%s"', position, copyts, duration, esc(pathname), esc(palette), esc(trim_filters), esc(gifname))
os.execute(args)
local ok, err, code = os.rename(gifname, gifname)
if ok then
msg.info("GIF created: " .. gifname)
mp.osd_message("GIF created: " .. gifname)
else
mp.osd_message("Error creating file, check CLI for more info.")
end
end
function set_gif_start()
start_time = mp.get_property_number("time-pos", -1)
mp.osd_message("GIF Start: " .. start_time)
end
function set_gif_end()
end_time = mp.get_property_number("time-pos", -1)
mp.osd_message("GIF End: " .. end_time)
end
function file_exists(name)
local f=io.open(name,"r")
if f~=nil then io.close(f) return true else return false end
end
mp.add_key_binding("g", "set_gif_start", set_gif_start)
mp.add_key_binding("G", "set_gif_end", set_gif_end)
mp.add_key_binding("Ctrl+g", "make_gif", make_gif)
mp.add_key_binding("Ctrl+G", "make_gif_with_subtitles", make_gif_with_subtitles)