class V2av
Attributes
duration[RW]
steps[RW]
Public Class Methods
new(src, srt, working_dir: '/tmp/v2av', debug: false, pollyspeech: {access_key: nil, secret_key: nil, voice_id: 'Amy', cache_filepath: '/tmp/v2av/pollyspeech/cache'})
click to toggle source
# File lib/v2av.rb, line 79 def initialize(src, srt, working_dir: '/tmp/v2av', debug: false, pollyspeech: {access_key: nil, secret_key: nil, voice_id: 'Amy', cache_filepath: '/tmp/v2av/pollyspeech/cache'}) @source, @working_dir, @debug = src, working_dir, debug @steps = srt.lines.map do |x| raw_time, desc = x.chomp.split(/ +/,2) OpenStruct.new({time: raw_time.to_i, desc: desc}) end s = `exiftool #{src}` puts 's: ' + s.inspect if @debug #a = s[/Duration.*(\d{1,2}:\d{2}:\d{2})/,1].split(':').map(&:to_i) #@duration = Subunit.new(units={minutes:60, hours:60, seconds: 0}, a).to_i @duration = s[/Duration.*: (\d+)/,1].to_i puts ('@duration: ' + @duration.inspect).debug if @debug @steps[0..-2].each.with_index do |x, i| x.duration = @steps[i+1].time - x.time end @steps.last.duration = @duration - @steps.last.time @pollyspeech = PollySpeech.new(pollyspeech) if pollyspeech[:access_key] end
Public Instance Methods
build(destination) { |self| ... }
click to toggle source
# File lib/v2av.rb, line 107 def build(destination) if block_given? then yield(self) else dir = File.dirname(@source) file = File.basename(@source) vid2 = File.join(@working_dir, file.sub(/\.mp4$/,'b\0')) trim_video @source, vid2 vid3 = File.join(@working_dir, file.sub(/\.mp4$/,'c.avi')) generate_audio add_audio_track File.join(@working_dir, 'audio.wav'), vid2, vid3 vid4 = File.join(dir, file.sub(/\.avi$/,'d\0')) resize_video vid3, vid4 vid5 = File.join(dir, file.sub(/\.mp4$/,'e\0')) transcode_video(vid4, vid5) add_subtitles(vid5, destination) end end
Private Instance Methods
add_audio_track(audio_file, video_file, target_video) { |audio_file, video_file, target_video| ... }
click to toggle source
adds the audio track to the video file mp4 in avi out
# File lib/v2av.rb, line 142 def add_audio_track(audio_file, video_file, target_video) if block_given? then yield(audio_file, video_file, target_video) else `ffmpeg -i #{video_file} -i #{audio_file} -codec copy -shortest #{target_video} -y` #"ffmpeg -i #{video_file} -i #{audio_file} -codec copy -shortest #{target_video} -y" end end
add_subtitles(source, destination) { |source, subtitles, destination| ... }
click to toggle source
mp4 in mp4 out
# File lib/v2av.rb, line 155 def add_subtitles(source, destination) subtitles = File.join(@working_dir, 's.srt') File.write subtitles, to_srt() if block_given? then yield(source, subtitles, destination) else `ffmpeg -i #{source} -i #{subtitles} -c copy -c:s mov_text #{destination} -y` end end
generate_audio(wav: true)
click to toggle source
# File lib/v2av.rb, line 169 def generate_audio(wav: true) return nil unless @pollyspeech @steps.each.with_index do |x, i| puts 'x.desc: ' + x.desc.inspect if @debug filename = "voice#{i+1}.ogg" x.audio = filename file = File.join(@working_dir, filename) @pollyspeech.tts(x.desc.force_encoding('UTF-8'), file) x.audio_duration = OggInfo.open(file) {|ogg| ogg.length.to_i } if @debug then puts ('x.duration: ' + x.duration.inspect).debug puts ('x.audio_duration: ' + x.audio_duration.inspect).debug end duration = x.duration - x.audio_duration x.silence_duration = duration >= 0 ? duration : 0 if wav then silent_file = File.join(@working_dir, "silence#{(i+1).to_s}.wav") puts 'x.silence_duration: ' + x.silence_duration.inspect if @debug wav_silence silent_file, duration: x.silence_duration ogg_to_wav File.join(@working_dir, "voice#{i+1}.ogg") end sleep 0.02 end if wav then intro = File.join(@working_dir, 'intro.wav') wav_silence intro files = @steps.length.times.flat_map do |n| [ File.join(@working_dir, "voice#{n+1}.wav"), File.join(@working_dir, "silence#{n+1}.wav") ] end files.prepend intro wav_concat files, File.join(@working_dir, 'audio.wav') end end
resize_video(source, destination)
click to toggle source
avi in avi out
# File lib/v2av.rb, line 225 def resize_video(source, destination) `ffmpeg -i #{source} -vf scale="720:-1" #{destination} -y` end
to_srt(offset=-(@steps.first.time - 1))
click to toggle source
# File lib/v2av.rb, line 230 def to_srt(offset=-(@steps.first.time - 1)) lines = to_subtitles(offset).strip.lines.map.with_index do |x, i| puts ('x: ' + x.inspect).debug if @debug raw_times, subtitle = x.split(/ /,2) puts ('raw_times: ' + raw_times.inspect).debug if @debug start_time, end_time = raw_times.split('-',2) times = [("%02d:%02d:%02d,000" % ([0, 0 ] + start_time.split(/\D/)\ .map(&:to_i)).reverse.take(3).reverse), \ '-->', \ ("%02d:%02d:%02d,000" % ([0, 0 ] + end_time.split(/\D/).map(&:to_i))\ .reverse.take(3).reverse)].join(' ') [i+1, times, subtitle].join("\n") end lines.join("\n") end
to_subtitles(offset=-(@steps.first.time - 1))
click to toggle source
# File lib/v2av.rb, line 252 def to_subtitles(offset=-(@steps.first.time - 1)) raw_times = @steps.map {|x| [x.time, x.time + x.audio_duration + 1]} times = raw_times.map do |x| x.map do |sec| a = Subunit.new(units={minutes:60}, seconds: sec+offset).to_h.to_a a.map {|x|"%d%s" % [x[1], x[0][0]] }.join('') end.join('-') end times.zip(@steps.map(&:desc)).map {|x| x.join(' ')}.join("\n") end
transcode_video(avi, mp4) { |avi, mp4| ... }
click to toggle source
# File lib/v2av.rb, line 270 def transcode_video(avi, mp4) if block_given? then yield(avi, mp4) else `ffmpeg -i #{avi} #{mp4} -y` end end
trim_video(video, newvideo)
click to toggle source
# File lib/v2av.rb, line 280 def trim_video(video, newvideo) start = @steps.first.time > 4 ? @steps.first.time - 4 : @steps.first.time t1, t2 = [start, @steps.last.time - 2 ].map do |step| "%02d:%02d:%02d" % (step.to_hms.reverse + [0,0]).take(3).reverse end `ffmpeg -i #{video} -ss #{t1} -t #{t2} -async 1 #{newvideo} -y` end