dotfiles2/base/.config/mpv/scripts/encoder.lua
2022-08-05 22:16:17 -07:00

195 lines
6 KiB
Lua

local mp = require('mp')
local utils = require('mp.utils')
local _config, _store_fn, _os_temp_dir, _subprocess
local encoder
------------------------------------------------------------
-- utility functions
local pad_timings = function(padding, start_time, end_time)
local video_duration = mp.get_property_number('duration')
start_time = start_time - padding
end_time = end_time + padding
if start_time < 0 then
start_time = 0
end
if end_time > video_duration then
end_time = video_duration
end
return start_time, end_time
end
local get_active_track = function(track_type)
local track_list = mp.get_property_native('track-list')
for _, track in pairs(track_list) do
if track.type == track_type and track.selected == true then
return track
end
end
return nil
end
------------------------------------------------------------
-- ffmpeg encoder
local ffmpeg = {}
ffmpeg.prefix = { "ffmpeg", "-hide_banner", "-nostdin", "-y", "-loglevel", "quiet", "-sn", }
ffmpeg.prepend = function(args)
if next(args) ~= nil then
for i, value in ipairs(ffmpeg.prefix) do
table.insert(args, i, value)
end
end
return args
end
ffmpeg.make_snapshot_args = function(source_path, output_path, timestamp)
return ffmpeg.prepend {
'-an',
'-ss', tostring(timestamp),
'-i', source_path,
'-map_metadata', '-1',
'-vcodec', _config.snapshot_codec,
'-lossless', '0',
'-compression_level', '6',
'-qscale:v', tostring(_config.snapshot_quality),
'-vf', string.format('scale=%d:%d', _config.snapshot_width, _config.snapshot_height),
'-vframes', '1',
output_path
}
end
ffmpeg.make_audio_args = function(source_path, output_path, start_timestamp, end_timestamp)
local audio_track = get_active_track('audio')
local audio_track_id = audio_track['ff-index']
if audio_track and audio_track.external == true then
source_path = audio_track['external-filename']
audio_track_id = 'a'
end
return ffmpeg.prepend {
'-vn',
'-ss', tostring(start_timestamp),
'-to', tostring(end_timestamp),
'-i', source_path,
'-map_metadata', '-1',
'-map', string.format("0:%d", audio_track_id),
'-ac', '1',
'-codec:a', _config.audio_codec,
'-vbr', 'on',
'-compression_level', '10',
'-application', 'voip',
'-b:a', tostring(_config.audio_bitrate),
'-filter:a', string.format("volume=%.1f", _config.tie_volumes and mp.get_property_native('volume') / 100 or 1),
output_path
}
end
------------------------------------------------------------
-- mpv encoder
local mpv = {}
mpv.make_snapshot_args = function(source_path, output_path, timestamp)
return {
'mpv',
source_path,
'--loop-file=no',
'--audio=no',
'--no-ocopy-metadata',
'--no-sub',
'--frames=1',
'--ovcopts-add=lossless=0',
'--ovcopts-add=compression_level=6',
table.concat { '--ovc=', _config.snapshot_codec },
table.concat { '-start=', timestamp },
table.concat { '--ovcopts-add=quality=', tostring(_config.snapshot_quality) },
table.concat { '--vf-add=scale=', _config.snapshot_width, ':', _config.snapshot_height },
table.concat { '-o=', output_path }
}
end
mpv.make_audio_args = function(source_path, output_path, start_timestamp, end_timestamp)
local audio_track = get_active_track('audio')
local audio_track_id = mp.get_property("aid")
if audio_track and audio_track.external == true then
source_path = audio_track['external-filename']
audio_track_id = 'auto'
end
return {
'mpv',
source_path,
'--loop-file=no',
'--video=no',
'--no-ocopy-metadata',
'--no-sub',
'--audio-channels=mono',
'--oacopts-add=vbr=on',
'--oacopts-add=application=voip',
'--oacopts-add=compression_level=10',
table.concat { '--oac=', _config.audio_codec },
table.concat { '--start=', start_timestamp },
table.concat { '--end=', end_timestamp },
table.concat { '--aid=', audio_track_id },
table.concat { '--volume=', _config.tie_volumes and mp.get_property('volume') or '100' },
table.concat { '--oacopts-add=b=', _config.audio_bitrate },
table.concat { '-o=', output_path }
}
end
------------------------------------------------------------
-- main interface
local create_snapshot = function(timestamp, filename)
local source_path = mp.get_property("path")
local output_path = utils.join_path(_os_temp_dir(), filename)
local args = encoder.make_snapshot_args(source_path, output_path, timestamp)
local on_finish = function()
_store_fn(filename, output_path)
os.remove(output_path)
end
_subprocess(args, on_finish)
end
local create_audio = function(start_timestamp, end_timestamp, filename, padding)
local source_path = mp.get_property("path")
local output_path = utils.join_path(_os_temp_dir(), filename)
if padding > 0 then
start_timestamp, end_timestamp = pad_timings(padding, start_timestamp, end_timestamp)
end
local args = encoder.make_audio_args(source_path, output_path, start_timestamp, end_timestamp)
for arg in string.gmatch(_config.use_ffmpeg and _config.ffmpeg_audio_args or _config.mpv_audio_args, "%S+") do
-- Prepend before output path
table.insert(args, #args, arg)
end
local on_finish = function()
_store_fn(filename, output_path)
os.remove(output_path)
end
_subprocess(args, on_finish)
end
local init = function(config, store_fn, os_temp_dir, subprocess)
_config = config
_store_fn = store_fn
_os_temp_dir = os_temp_dir
_subprocess = subprocess
encoder = config.use_ffmpeg and ffmpeg or mpv
end
return {
init = init,
create_snapshot = create_snapshot,
create_audio = create_audio,
}