Skip to content

Instantly share code, notes, and snippets.

@koyachi
Created March 29, 2009 16:49
Show Gist options
  • Save koyachi/87459 to your computer and use it in GitHub Desktop.
Save koyachi/87459 to your computer and use it in GitHub Desktop.
class Array
def shuffle!
size.downto(1) { |n| push delete_at(rand(n)) }
self
end
end
class Command
def initialize(cmd)
@cmd = cmd
end
def run(options)
command = [@cmd, options].flatten.join ' '
puts "run: #{command}\n"
system command
end
end
class VideoEditor
def initialize(args)
@ffmpeg = Command.new 'ffmpeg'
class << @ffmpeg
def extract_mp3(args)
p args
self.run "-i #{args[:input_video]} #{args[:output_mp3]}"
end
def flv2avi(args)
# output_video = args[:input_video].sub(/^(.*)\.flv$/, '$1.avi')
self.run "-i #{args[:input_video]} #{args[:output_video]}"
args[:output_video]
end
def divide_video(args)
self.run "-i #{args[:input_video]} -ss #{args[:start]} -t #{args[:duration]} #{args[:output_video]}"
end
def encode(args)
self.run "-i #{args[:input_video]} -vcodec #{args[:vcodec]} -acodec #{args[:acodec]} #{args[:output_video]}"
end
end
@mencoder = Command.new 'mencoder'
class << @mencoder
def concat(args)
self.run(args[:input_videos].join(' ') + " -o #{args[:output_video]} -oac copy -ovc copy")
end
end
@echonest = WebService::EchoNest.new args[:api_key]
end
def prepare_workspace(args)
@work_dir = "ws_#{DateTime.now.strftime '%F--%02H-%02M-%02S'}_#{args[:id]}"
puts @work_dir
Dir.mkdir @work_dir
@work_dir
end
def prepare_workvideos(args)
work_avis = []
args[:videos].each do |v|
work_avi = "#{@work_dir}/#{v}.avi"
@ffmpeg.flv2avi :input_video => v,
:output_video => work_avi
work_avis.push work_avi
end
work_avis
end
def post_production(args)
# mencoderでくっつけただけだと再生失敗する可能性がある。
# 配布用に適当なフォーマットでエンコード
@ffmpeg.encode :input_video => args[:input_video],
:output_video => args[:output_video],
:vcodec => 'msmpeg4v2',
:acodec => 'mp2'
end
def dump_analyzed_data(args)
end
# action
def shuffle_8beats
# extract_mp3
# analyze_audio
# collect_8beat
# divide_video
# concat_video
end
def shuffle_segments(args)
file_path = args[:input_video].split('/').join[0..-2]
file_id = args[:input_video].sub(/\..*?$/, "")
ws_dir = prepare_workspace(:id => args[:input_video])
work_avis = prepare_workvideos :videos => [args[:input_video]]
audio_file = "#{ws_dir + '/' + file_id}.mp3"
extract_mp3 :input_video => args[:input_video],
:output_mp3 => audio_file
# analyze_audio :input_audio => audio_file
analyzed_data = @echonest.get_segments :file => audio_file
p @analyzed_data
puts "\n"
analyzed_data[:segments].each_with_index do |segment, i|
puts "#{segment[:start]} - #{segment[:duration]}\n"
end
# collect_8beat
# divide_video
# concat_video
end
# :videos = [v1, v2,..]
def mix_videos(args)
puts "[[ mix_videos ]]\n"
ws_dir = prepare_workspace :id => 'mix_videos'
work_avis = prepare_workvideos :videos => args[:input_videos]
analyzed_data = []
sorted_data = []
bead_index = []
puts "[[ analyzing... ]]\n"
args[:input_videos].each do |input_video|
file_path = input_video.split('/').join[0..-2]
file_id = input_video.sub(/\..*?$/, "")
audio_file = "#{ws_dir + '/' + file_id}.mp3"
extract_mp3 :input_video => input_video,
:output_mp3 => audio_file
res_beats = @echonest.get_beats :file => audio_file
song_id = res_beats[:query][:id]
res_sections = @echonest.get_sections :id => song_id
p @analyzed_data
puts "\n"
end
# それぞれをソートして違うソースの近いbeatを探す
puts "[[ sorting... ]]\n"
analyzed_data.each do |data|
end
end
def shuffle_sections(args)
file_path = args[:input_video].split('/').join[0..-2]
file_id = args[:input_video].sub(/\..*?$/, "")
puts "[[ prepare ]]\n"
ws_dir = prepare_workspace(:id => args[:input_video])
work_avis = prepare_workvideos :videos => [args[:input_video]]
audio_file = "#{ws_dir + '/' + file_id}.mp3"
puts "[[ extract mp3 ]]\n"
extract_mp3 :input_video => args[:input_video],
:output_mp3 => audio_file
puts "[[ get sections ]]\n"
res_sections = @echonest.get_sections :file => audio_file
p res_sections
puts "\n"
res_sections[:sections].shuffle!
shuffled_section_videos = [];
puts "[[ divide videos ]]\n"
res_sections[:sections].each_with_index do |section, i|
output_video = "#{work_avis[0]}_section#{i}.avi"
divide_video :input_video => work_avis[0],
:start => section[:start],
:duration => section[:duration],
:output_video => output_video
shuffled_section_videos.push output_video
end
puts "[[ concat videos ]]\n"
cat_video = "#{ws_dir}/shuffled_sections.avi"
concat_videos :input_videos => shuffled_section_videos,
:output_video => cat_video
puts "[[ post production ]]\n"
post_production :input_video => cat_video,
:output_video => "#{ws_dir}/shuffled_sections_#{file_id}.avi"
end
# セクション単位で適当なとこでリピート
# 基本的にながれのまま
def edit_1(args)
file_path = args[:input_video].split('/').join[0..-2]
file_id = args[:input_video].sub(/\..*?$/, "")
puts "[[ prepare ]]\n"
ws_dir = prepare_workspace(:id => args[:input_video])
work_avis = prepare_workvideos :videos => [args[:input_video]]
audio_file = "#{ws_dir + '/' + file_id}.mp3"
puts "[[ extract mp3 ]]\n"
extract_mp3 :input_video => args[:input_video],
:output_mp3 => audio_file
puts "[[ get sections ]]\n"
res_sections = @echonest.get_sections :file => audio_file
p res_sections
puts "\n"
song_md5 = res_sections[:query][:md5]
puts "[[ get beats ]]\n"
res_beats = @echonest.get_beats :md5 => song_md5
p res_beats
section_videos = [];
puts "[[ divide videos ]]\n"
res_sections[:sections].each_with_index do |section, i|
puts "#### section #{i} ####\n"
# output_video = "#{work_avis[0]}_section#{i}.avi"
# divide_video :input_video => work_avis[0],
# n :start => section[:start],
# :duration => section[:duration],
# :output_video => output_video
# section_videos.push output_video
# unshiftが正解?
# res_beats[:beats][0][:value] = 0
# res_beats[:beat].unshift {:confidence => 0, :value => 0}
# prev = res_beats[:beats][0]
prev = {:value => 0.0}
beats = []
sec_start = Float(section[:start])
sec_end = Float(section[:start]) + Float(section[:duration])
res_beats[:beats].each_with_index do |beat, j|
puts "#### beats #{j} ####\n"
current = {
:start => Float(prev[:value]),
:duration => Float(beat[:value]) - Float(prev[:value])
}
current[:end] = current[:start] + current[:duration]
if current[:start] >= sec_start && current[:end] < sec_end
if j % 8 == 0
0.upto(Integer(rand * 6)) {|k| beats.push current}
end
beats.push current
elsif current[:start] > sec_end
break
end
prev = beat
end
# first_duration = beats[0][:duration]
# beats.unshift({:start => 0.0, :duration => first_duration})
p beats
# beatごとに分割
divided_beats_index = {}
beats.each_with_index do |beat,j|
if divided_beats_index[beat[:start]]
section_videos.push divided_beats_index[beat[:start]]
next
end
output_video = "#{work_avis[0]}_section#{i}_beat#{j}.avi"
divided_beats_index[beat[:start]] = output_video
divide_video :input_video => work_avis[0],
:start => beat[:start],
:duration => beat[:duration],
:output_video => output_video
section_videos.push output_video
end
end
puts "[[ concat videos ]]\n"
cat_video = "#{ws_dir}/edit_1.avi"
concat_videos :input_videos => section_videos,
:output_video => cat_video
puts "[[ post production ]]\n"
post_production :input_video => cat_video,
:output_video => "#{ws_dir}/edit_1_#{file_id}.avi"
end
# commands
def extract_mp3(args)
@ffmpeg.extract_mp3 args
end
# def analyze_audio(args)
# @analyzed_audio = @echonest.get_beats :file => args[:input_audio]
# end
def collect_8beat
beat8s = []
@analyzed_audio[:beats].each do |beat|
p beat
end
end
def divide_video(args)
@ffmpeg.divide_video(:input_video => args[:input_video],
:start => args[:start],
:duration => args[:duration],
:output_video => args[:output_video])
end
def concat_videos(args)
p args
@mencoder.concat(:input_videos => args[:input_videos],
:output_video => args[:output_video])
end
end
p 'start program'
config = Mash.new YAML.load(File.open('config.yaml'))
#en = WebService::EchoNest.new config[:api_key]
ve = VideoEditor.new :api_key => config[:api_key]
#ve.shuffle_segments :input_video => 'FredvomJupiter.flv'
#ve.shuffle_sections :input_video => 'FredvomJupiter.flv'
#ve.shuffle_sections :input_video => ARGV[0]
ve.edit_1 :input_video => ARGV[0]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment