require 'open3' module FlyAdmin module Convertable extend ::ActiveSupport::Concern module ClassMethods end def process CONVERTATION_LOG.info "video_#{self.id}: start processing" begin movie = FFMPEG::Movie.new(self.full_source_path) create_dir(self.high_content_path) create_dir(self.low_content_path) dir = create_dir(Rails.root.to_s + '/tmp/ffmpeg/*') Dir.chdir(dir) convert('-codec:v libvpx -b:v 360k -codec:a libvorbis -b:a 60k -ac 2 -s 640x360 -movflags +faststart -f webm', 'low/movie.webm', WEBM_LOW_MASK ) if (self.encode_mask & WEBM_LOW_MASK == 0) convert('-codec:v libvpx -b:v 1000k -codec:a libvorbis -b:a 80k -ac 2 -s 1280x720 -movflags +faststart -f webm', 'high/movie.webm', WEBM_HIGH_MASK ) if (self.encode_mask & WEBM_HIGH_MASK == 0) convert("-codec:v libx264 -b:v 360k -maxrate 360k -bufsize 720k -movflags +faststart -vprofile high -preset slow -vf 'scale=trunc(iw/2)*2:360' -threads 0 -codec:a libfdk_aac -b:a 96k -ac 2 -f mp4", 'low/movie.mp4', MP4_LOW_MASK) if (self.encode_mask & MP4_LOW_MASK == 0) convert("-codec:v libx264 -b:v 1000k -maxrate 1000k -bufsize 2000k -movflags +faststart -vprofile high -preset slow -vf 'scale=trunc(iw/2)*2:720' -threads 0 -codec:a libfdk_aac -b:a 128k -ac 2 -f mp4", 'high/movie.mp4', MP4_HIGH_MASK) if (self.encode_mask & MP4_HIGH_MASK == 0) Dir.chdir(Rails.root.to_s) rescue Exception => e CONVERTATION_LOG.error "#{e.message}\n\t#{e.backtrace}" return "#{e.message}\n\t#{e.backtrace.join("\n\t")}" end return nil end def convert(options, outfile, mask) log_file = "#{Rails.root}/log/ffmpeg_convertation.log" pid_file = "#{Rails.root}/tmp/pids/ffmpeg_pids.pid" cmd = "ffmpeg -i #{full_source_path.shellescape} #{options} -threads 0 -y #{self.path + outfile}"# >> #{logfile} 2>&1" success_convert = 0 fork do Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr| CONVERTATION_LOG.info "video_#{id} #{FORMAT[mask]} started" pid = wait_thr.pid File.open(pid_file, "a") { |f| f.puts("video_#{id} with pid: #{pid}") } captured_stdout = stdout.read captured_stderr = stderr.read exit_status = wait_thr.value if exit_status.success? self.reload(:select => "encode_mask") self.update_column(:encode_mask, encode_mask + mask) CONVERTATION_LOG.info "video_#{id} #{FORMAT[mask]} done!" else File.open(log_file, "a") do |f| captured_stdout.each_line { |line| f.puts(line) } captured_stderr.each_line { |line| f.puts(line) } end CONVERTATION_LOG.info "video_#{id} #{FORMAT[mask]} failed!" end end end Process.wait end def create_dir(dir_path) dir = File.dirname(dir_path) unless File.directory?(dir) FileUtils.mkdir_p(dir) end dir end def set_duration movie = FFMPEG::Movie.new(full_source_path) self.duration = movie.duration.to_i save! end # def remove_content # FileUtils.rm_rf self.path # end # Path helpers def full_source_path SiteConfig['torrents_path'] + source_path end def low_content_path self.path + 'low/movie.mp4' end def high_content_path self.path + 'high/movie.mp4' end def path Rails.root.to_s + "/public/uploads/video/content/#{self.id}/" end def content_path Rails.root.to_s + "/public/uploads/video/content/#{self.id}/#{self.content}" end def url "/uploads/video/content/#{self.id}/" end def low_content_url self.url + 'low/movie.mp4' end def high_content_url self.url + 'high/movie.mp4' end def alter_low_content_url self.url + 'low/movie.webm' end def alter_high_content_url self.url + 'high/movie.webm' end # Constants PENDING_STATE = 0 CONVERTED_STATE = 1 FAILURE_STATE = 2 BEFORE_SPAWNLING = 3 WEBM_LOW_MASK = 0b0001 WEBM_HIGH_MASK = 0b0010 MP4_LOW_MASK = 0b0100 MP4_HIGH_MASK = 0b1000 FORMAT = {WEBM_LOW_MASK => 'webm 360p', WEBM_HIGH_MASK => 'webm 720p', MP4_LOW_MASK => 'mp4 360p', MP4_HIGH_MASK => 'mp4 720p'} STATE = {0 => 'pending', 1 => 'converted', 2 => 'failure', 3 => 'before spawnling'} end end