Created
March 29, 2009 16:49
-
-
Save koyachi/87459 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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