-
-
Save stevenkolstad/1238670 to your computer and use it in GitHub Desktop.
video encoder snippet
This file contains 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 Attachment < ActiveRecord::Base | |
belongs_to :post | |
mount_uploader :filename, PostAttachmentUploader | |
VIDEO_FORMATS = %W{ogv mp4 webm} | |
PREVIEW_FORMAT = "jpeg" | |
before_save :set_metas | |
after_create :start_encoding!, :if => :video? | |
def display_name | |
filename.to_s.split("/").last | |
end | |
def start_encoding! | |
VideoEncoder.process_async(self) | |
end | |
def force_encode(format) | |
VideoEncoder.new(filename.path).encode_to(format.to_s, path_for(format)) | |
end | |
def video? | |
view_as == "video" | |
end | |
def video_thumbnail | |
return "" unless video_ready? | |
url_for(PREVIEW_FORMAT) | |
end | |
def check_if_video_done | |
missing = [] | |
(VIDEO_FORMATS + [PREVIEW_FORMAT]).each do |format| | |
missing << path_for(format) unless File.exist?(path_for(format)) | |
end | |
if missing.empty? | |
update_attribute(:video_ready, 1) | |
end | |
missing | |
end | |
def filename_for(format) | |
fname = File.basename(filename.to_s, File.extname(filename.to_s)) | |
"#{fname}_converted.#{format}" | |
end | |
def path_for(format) | |
fname = File.basename(filename.to_s) | |
filename.path.chomp(fname) + filename_for(format) | |
end | |
def url_for(format) | |
fname = File.basename(filename.to_s) | |
filename.url.chomp(fname) + filename_for(format) | |
end | |
def set_metas | |
self.size = File.size(filename.path) | |
extname = File.extname(filename.path).downcase | |
self.view_as = | |
if %W{.png .jpg .jpeg .gif .bmp .tiff}.include?(extname) | |
"picture" | |
elsif %W{.doc .docx .pdf .rtf .txt}.include?(extname) | |
"document" | |
elsif %W{.avi .mp4 .ogv .webm .mpg .mpeg .flv .mkv .wmv }.include?(extname) | |
"video" | |
else | |
"other" | |
end | |
end | |
end |
This file contains 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 Jobs::Encoder | |
def initialize(id, format) | |
@id = id | |
@format = format | |
end | |
def perform | |
attachment = Attachment.find(@id) | |
VideoEncoder.new(attachment.filename.path).encode_to(@format, attachment.path_for(@format)) | |
attachment.check_if_video_done | |
end | |
end |
This file contains 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
# encoding: utf-8 | |
class PostAttachmentUploader < CarrierWave::Uploader::Base | |
include CarrierWave::MiniMagick | |
storage :file | |
def store_dir | |
"system/#{model.class.to_s.underscore}/#{model.id}" | |
end | |
end |
This file contains 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 VideoEncoder | |
WIDTH = 480 | |
HEIGHT = 320 | |
def self.process_async(attachment) | |
(attachment.class::VIDEO_FORMATS + [attachment.class::PREVIEW_FORMAT]).each do |format| | |
Delayed::Job.enqueue Jobs::Encoder.new(attachment.id, format) | |
end | |
end | |
def initialize(filename) | |
@filename = filename | |
end | |
def encode_to(format, output_file) | |
case format | |
when "ogv" then encode_ogv(output_file) | |
when "mp4" then encode_mp4(output_file) | |
when "webm" then encode_webm(output_file) | |
when "jpeg" then encode_jpeg(output_file) | |
end | |
end | |
def encode_ogv(output_file) | |
delete_old_file(output_file) | |
command = %{ffmpeg2theora --videoquality 5 --audioquality 1 --max_size #{ratio} \ | |
--output #{output_file} #{@filename}} | |
run_cmd(command) | |
end | |
def encode_mp4(output_file) | |
delete_old_file(output_file) | |
command = %{HandBrakeCLI --preset "iPhone & iPod Touch" --width #{WIDTH} --vb 600 --two-pass \ | |
--input #{@filename} --output #{output_file}} | |
run_cmd(command) | |
end | |
def encode_webm(output_file) | |
delete_old_file(output_file) | |
delete_old_file(output_file + "-0.log") | |
delete_old_file(output_file + "-tmp.webm") | |
command1 = %{ffmpeg -pass 1 -passlogfile #{@filename} -threads 16 -keyint_min 0 -g 250 \ | |
-skip_threshold 0 -qmin 1 -qmax 51 -i #{@filename} -vcodec libvpx -s #{ratio} \ | |
-aspect 4:3 -an -y #{output_file}-tmp.webm} | |
run_cmd(command1) | |
command2 = %{ffmpeg -pass 2 -passlogfile #{@filename} -threads 16 -keyint_min 0 -g 250 \ | |
-skip_threshold 0 -qmin 1 -qmax 51 -i #{@filename} -vcodec libvpx -b 614400 -s #{ratio} \ | |
-aspect 4:3 -acodec libvorbis -ar 44100 -ab 64k -y #{output_file}} | |
run_cmd(command2) | |
run_cmd("rm #{output_file}-tmp.webm") | |
end | |
def encode_jpeg(output_file) | |
delete_old_file(output_file) | |
begin | |
info = run_cmd("ffmpeg -i #{@filename} -f null /dev/null 2>&1") | |
duration_line = info.match(/Duration:\s+([0-9:\.]+)/) | |
duration = duration_line[1].split(":").last.to_f | |
center = (duration / 2).round | |
rescue => e | |
puts e.message | |
center = 1 | |
end | |
command = %{ffmpeg -itsoffset -#{center} -i #{@filename} -vcodec mjpeg -vframes 1 -an -f rawvideo \ | |
-s #{ratio} #{output_file}} | |
run_cmd(command) | |
end | |
def run_cmd(command) | |
puts command | |
system(command) | |
end | |
def delete_old_file(file) | |
run_cmd("rm #{file}") if File.exist?(file) | |
end | |
def ratio | |
"#{WIDTH}x#{HEIGHT}" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment