encoder.lua (6418B)
1 local mp = require('mp') 2 local utils = require('mp.utils') 3 local helpers = require('helpers') 4 local _config, _store_fn, _os_temp_dir, _subprocess 5 local encoder 6 7 ------------------------------------------------------------ 8 -- utility functions 9 10 local pad_timings = function(padding, start_time, end_time) 11 local video_duration = mp.get_property_number('duration') 12 start_time = start_time - padding 13 end_time = end_time + padding 14 15 if start_time < 0 then 16 start_time = 0 17 end 18 19 if end_time > video_duration then 20 end_time = video_duration 21 end 22 23 return start_time, end_time 24 end 25 26 local get_active_track = function(track_type) 27 local track_list = mp.get_property_native('track-list') 28 for _, track in pairs(track_list) do 29 if track.type == track_type and track.selected == true then 30 return track 31 end 32 end 33 return nil 34 end 35 36 ------------------------------------------------------------ 37 -- ffmpeg encoder 38 39 local ffmpeg = {} 40 41 ffmpeg.prefix = { "ffmpeg", "-hide_banner", "-nostdin", "-y", "-loglevel", "quiet", "-sn", } 42 43 ffmpeg.prepend = function(args) 44 if next(args) ~= nil then 45 for i, value in ipairs(ffmpeg.prefix) do 46 table.insert(args, i, value) 47 end 48 end 49 return args 50 end 51 52 ffmpeg.make_snapshot_args = function(source_path, output_path, timestamp) 53 return ffmpeg.prepend { 54 '-an', 55 '-ss', tostring(timestamp), 56 '-i', source_path, 57 '-map_metadata', '-1', 58 '-vcodec', _config.snapshot_codec, 59 '-lossless', '0', 60 '-compression_level', '6', 61 '-qscale:v', tostring(_config.snapshot_quality), 62 '-vf', string.format('scale=%d:%d', _config.snapshot_width, _config.snapshot_height), 63 '-vframes', '1', 64 output_path 65 } 66 end 67 68 ffmpeg.make_audio_args = function(source_path, output_path, start_timestamp, end_timestamp) 69 local audio_track = get_active_track('audio') 70 local audio_track_id = audio_track['ff-index'] 71 72 if audio_track and audio_track.external == true then 73 source_path = audio_track['external-filename'] 74 audio_track_id = 'a' 75 end 76 77 return ffmpeg.prepend { 78 '-vn', 79 '-ss', tostring(start_timestamp), 80 '-to', tostring(end_timestamp), 81 '-i', source_path, 82 '-map_metadata', '-1', 83 '-map', string.format("0:%d", audio_track_id), 84 '-ac', '1', 85 '-codec:a', _config.audio_codec, 86 '-vbr', 'on', 87 '-compression_level', '10', 88 '-application', 'voip', 89 '-b:a', tostring(_config.audio_bitrate), 90 '-filter:a', string.format("volume=%.1f", _config.tie_volumes and mp.get_property_native('volume') / 100 or 1), 91 output_path 92 } 93 end 94 95 ------------------------------------------------------------ 96 -- mpv encoder 97 98 local mpv = {} 99 100 mpv.make_snapshot_args = function(source_path, output_path, timestamp) 101 return { 102 'mpv', 103 source_path, 104 '--loop-file=no', 105 '--audio=no', 106 '--no-ocopy-metadata', 107 '--no-sub', 108 '--frames=1', 109 '--ovcopts-add=lossless=0', 110 '--ovcopts-add=compression_level=6', 111 table.concat { '--ovc=', _config.snapshot_codec }, 112 table.concat { '-start=', timestamp }, 113 table.concat { '--ovcopts-add=quality=', tostring(_config.snapshot_quality) }, 114 table.concat { '--vf-add=scale=', _config.snapshot_width, ':', _config.snapshot_height }, 115 table.concat { '-o=', output_path } 116 } 117 end 118 119 mpv.make_audio_args = function(source_path, output_path, start_timestamp, end_timestamp) 120 local audio_track = get_active_track('audio') 121 local audio_track_id = mp.get_property("aid") 122 123 if audio_track and audio_track.external == true then 124 source_path = audio_track['external-filename'] 125 audio_track_id = 'auto' 126 end 127 128 return { 129 'mpv', 130 source_path, 131 '--loop-file=no', 132 '--video=no', 133 '--no-ocopy-metadata', 134 '--no-sub', 135 '--audio-channels=mono', 136 '--oacopts-add=vbr=on', 137 '--oacopts-add=application=voip', 138 '--oacopts-add=compression_level=10', 139 table.concat { '--oac=', _config.audio_codec }, 140 table.concat { '--start=', start_timestamp }, 141 table.concat { '--end=', end_timestamp }, 142 table.concat { '--aid=', audio_track_id }, 143 table.concat { '--volume=', _config.tie_volumes and mp.get_property('volume') or '100' }, 144 table.concat { '--oacopts-add=b=', _config.audio_bitrate }, 145 table.concat { '-o=', output_path } 146 } 147 end 148 149 ------------------------------------------------------------ 150 -- main interface 151 152 local create_snapshot = function(timestamp, filename) 153 if _config.create_image == true then 154 local source_path = mp.get_property("path") 155 local output_path = utils.join_path(_os_temp_dir(), filename) 156 local args = encoder.make_snapshot_args(source_path, output_path, timestamp) 157 local on_finish = function() 158 helpers.notify(string.format("File stored: '%s'.", filename)) 159 end 160 _subprocess(args, on_finish) 161 else 162 print("Snapshot will not be created.") 163 end 164 end 165 166 local create_audio = function(start_timestamp, end_timestamp, filename, padding) 167 if not helpers.is_empty(_config.audio_field) then 168 local source_path = mp.get_property("path") 169 local output_path = utils.join_path(_os_temp_dir(), filename) 170 171 if padding > 0 then 172 start_timestamp, end_timestamp = pad_timings(padding, start_timestamp, end_timestamp) 173 end 174 175 local args = encoder.make_audio_args(source_path, output_path, start_timestamp, end_timestamp) 176 for arg in string.gmatch(_config.use_ffmpeg and _config.ffmpeg_audio_args or _config.mpv_audio_args, "%S+") do 177 -- Prepend before output path 178 table.insert(args, #args, arg) 179 end 180 local on_finish = function() 181 helpers.notify(string.format("File stored: '%s'.", filename)) 182 end 183 _subprocess(args, on_finish) 184 else 185 print("Audio will not be created.") 186 end 187 end 188 189 local init = function(config, os_temp_dir, subprocess) 190 _config = config 191 _os_temp_dir = os_temp_dir 192 _subprocess = subprocess 193 encoder = config.use_ffmpeg and ffmpeg or mpv 194 end 195 196 return { 197 init = init, 198 create_snapshot = create_snapshot, 199 create_audio = create_audio, 200 }