mpv2oboeru

mpv helpers to create flashcards from movies and TV shows
git clone anongit@rnpnr.xyz:mpv2oboeru.git
Log | Files | Refs | Feed | README | LICENSE

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 }