It’s about time I write on this thing since it has been months since my last post. I was sifting through some old code I’d written last year and I tell you what, sometimes I’m actually shocked at the things I’ve written that I have forgotten about. For instance, I had a client who wanted not only the ability to upload videos, but also link to videos through YouTube. Sounds easy right? Okay but make the videos play in the same player, and make them look like there is no difference. Not so easy. It took a lot of scrounging since this was last year, prior to the YouTube API, however it became a very fun little project involving ffmpeg and rvideo.
Basically what happens is if a video has a YouTube ID, then go get the thumbnail image and the original MPEG file from YouTube and convert it to flv before saving. If the user uploads a video, use ffmpeg to grab a still of the first frame to use as the thumbnail, then convert it to flv and save it.
I present thee Video model. (Unfortunately this was so long ago, I was using attachment_fu… maybe Paperclip would have helped a bit.)
class Video < ActiveRecord::Base
include AASM
aasm_column :state
aasm_initial_state :pending
aasm_state :pending
aasm_state :converting
aasm_state :converted, :enter => :set_new_filename
aasm_state :error
aasm_event :convert do
transitions :from => :pending, :to => :converting
end
aasm_event :converted do
transitions :from => :converting, :to => :converted
end
aasm_event :failure do
transitions :from => :converting, :to => :error
end
def get_yt_video_data
uri = URI.parse("http://www.youtube.com/get_video_info")
post_args = { 'video_id' => self.url }
res, data = Net::HTTP.post_form uri, post_args
b = res.body
CGI::parse(b) ## return a hash of k=>v pairs
end
def get_yt_video_thumb
get_yt_video_data["thumbnail_url"].first
end
def get_yt_video_duration
seconds = get_yt_video_data["length_seconds"].first.to_i ## format this better... seconds/60 = mins/60 = hours ... hh:mm:ss
total_minutes = seconds / 1.minutes
seconds_in_last_minute = seconds - total_minutes.minutes.seconds
"#{total_minutes}:#{seconds_in_last_minute}"
end
def get_yt_embed_url
return CGI::escape("#{public_filename}") unless self.url.present?
data = get_yt_video_data
fmt = '';
fmt_map = data["fmt_map"]
a = fmt_map[0..2]
if a == '18/'
fmt = '18'
elsif a == '22/'
fmt = '22'
break
end
token = data["token"]
uri2 = URI.parse("http://www.youtube.com")
args2 = {:video_id => url, :t => token, :fmt => fmt }
qstr = "video_id=#{url}&t=#{token}&fmt=18"
res = ""
Net::HTTP.start(uri2.host, uri2.port) {|http|
res = http.head("/get_video?#{qstr}")
}
CGI::escape("#{res.header['Location']}")
end
protected
def after_create
return true if url.present?
convert
end
def convert
self.convert!
spawn do
success = system("ffmpeg -i #{full_filename} -ar 22050 -s 480x320 -f flv -y #{full_filename}.flv")
if success && $?.exitstatus == 0
self.converted!
else
self.failure!
end
end
end
def create_thumbnail
system "ffmpeg -i #{full_filename}.flv -s 120x90 -vframes 1 -f image2 -an #{full_filename}.jpg"
end
def set_new_filename
create_thumbnail
update_attribute(:filename, "#{filename}.flv")
update_attribute(:content_type, "application/x-flash-video")
update_attribute(:width, "480")
update_attribute(:height, "320")
end
end
No related posts.
Related posts brought to you by Yet Another Related Posts Plugin.