Welcome back to part 2 of How to create a video upload platform using Ruby on Rails. In Part 1, we worked on setting up the basic Ruby on Rails application that allowed us to upload, store, and playback video files from our app. In this next part, we are going to enhance that process some by adding some FFMPEG Transcoding. This way, we can get all videos that are uploaded converted into a common format that will make it easier to work with on the playback side.
So lets get started. The first thing we need to do is make sure we have ffmpeg
installed. On mac this is pretty simple using brew
. If you don’t have HomeBrew installed, please follow the directions at https://brew.sh/. If you are on another linux or windows system, there are many guides online to help set ffmpeg
up for you. Once you have that installed, we can install the ffmpeg
command:
brew install ffmpeg
I decided to install a lot of the extra ffmpeg options to make sure I had the best compatibility. Here is a more complete line
brew install ffmpeg --with-chromaprint --with-fdk-aac --with-libass --with-librsvg --with-libsoxr --with-libssh --with-tesseract --with-libvidstab --with-opencore-amr --with-openh264 --with-openjpeg --with-openssl --with-rtmpdump --with-rubberband --with-sdl2 --with-snappy --with-tools --with-webp --with-x265 --with-xz --with-zeromq --with-zimg
Once you have ffmpeg installed and running we need to add the carrierwave-video
gem to our project:
# Gemfile
gem "carrierwave-video"
Next, we need to update our upload to include this new library. Open the app/uploaders/video_uploader.rb
file and add the following include
line to it:
class VideoUploader < CarrierWave::Uploader::Base
include CarrierWave::Video # <== Add this line here
...
In order for Carrierwave to actually encode the video, we need to also add a line that instructs it to do so. Lets also adjust the resolution while we are at it.
class VideoUploader < CarrierWave::Uploader::Base
include CarrierWave::Video
process encode_video: [:mp4, resolution: "640x480"]
...
The last thing we need to do is change the file extension. If we upload an avi
or mov
file, we convert that to mp4
but with Carrierwave it will maintain the original extension. So add the following lines right after the process
line added above
def full_filename(for_file)
super.chomp(File.extname(super)) + '.mp4'
end
def filename
original_filename.chomp(File.extname(original_filename)) + '.mp4'
end
Fire up your Rails app and upload a video just like we did in Part 1. You should see the following in your Rails console. Notice the line Running transcoding...
Started POST "/videos" for 127.0.0.1 at 2018-05-17 09:41:10 -0400
Processing by VideosController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"pCgWw3lxulQ9qiGxfck5oqFXgQo0tqO7gG371YEbFaiiRMdAc98uPGQCvTYzn0/Kub/pQtQI9n95I+grmGvQ6w==", "video"=>{"title"=>"adf", "file"=>#<ActionDispatch::Http::UploadedFile:0x007fbb5f814be8 @tempfile=#<Tempfile:/var/folders/__/7ns9m_817l71zfd0xw5618n00000gn/T/RackMultipart20180517-60568-c6cwal.mov>, @original_filename="step.mov", @content_type="video/quicktime", @headers="Content-Disposition: form-data; name=\"video[file]\"; filename=\"step.mov\"\r\nContent-Type: video/quicktime\r\n">}, "commit"=>"Create Video"}
I, [2018-05-17T09:41:10.439284 #60568] INFO -- : Running transcoding...
["/usr/local/bin/ffmpeg", "-y", "-i", "/Sites/VideoSite/tmp/1526564470-60568-0006-7430/step.mov", "-vcodec", "libx264", "-acodec", "aac", "-s", "640x480", "-r", "30", "-strict", "-2", "-map_metadata", "-1", "-aspect", "1.3333333333333333", "/Sites/VideoSite/tmp/1526564470-60568-0006-7430/tmpfile.mp4"]
I, [2018-05-17T09:41:17.640387 #60568] INFO -- : Transcoding of /Sites/VideoSite/tmp/1526564470-60568-0006-7430/step.mov to /Sites/VideoSite/tmp/1526564470-60568-0006-7430/tmpfile.mp4 succeeded
(0.3ms) begin transaction
SQL (0.3ms) INSERT INTO "videos" ("title", "file", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["title", "adf"], ["file", "step.mp4"], ["created_at", "2018-05-17 13:41:17.643006"], ["updated_at", "2018-05-17 13:41:17.643006"]]
(1.0ms) commit transaction
Redirected to http://localhost:3000/videos/1
Completed 302 Found in 7260ms (ActiveRecord: 1.6ms)
There we go. We are now successfully encoding the video file to a common format using ffmpeg
. In the next part we will look at moving this process to the background so that we don’t force the user to wait on the transcoding, and add some status indications of how the progress is going. Until next time!