Video Upload/Processing with Ruby on Rails
This article is about an issue I struggled for more than 10 hours. And I am pretty excited to tell you guys about this.
Things in my article
- Existing Architecture with Carrierwave GEM
- The Issue I faced
- What is FFMPEG?
- What I did to fix the issue?
Existing Architecture with Carrierwave GEM
The application I am talking about today has an API which receives media content from mobile devices. Once received it should be saved in the server and also generate the following items from the media type “VIDEO”.
- Raw video file
- Scaled video file (less size, quality)
- Thumbnail image
I managed to succeed this feature with the following gems.
# Carrierwave
gem 'carrierwave-video'
gem 'carrierwave-video-thumbnailer'
gem 'carrierwave_backgrounder'
gem 'streamio-ffmpeg', '~> 2.0.0'# Delayed job used by carrierwave_backgrounder
gem 'delayed_job_active_record'
Basically I have created a pretty easy architecture on this,
My CarrierwaveVideo Model looks like this
Mounted Video Uploader from CarrierwaveVideo gem looks like this
This works well actually…
Here is the problem..
The Issue I faced
Once a video uploaded it should look like this.
But…. Once a video uploaded form Android device, the re-scaled video looks like this, ( after encoding the video )
The video process (encoding) works nicely for the iOS device generated video but not for the android generated videos. Even though I change the encoding attributes it didn’t fix the problem.
Some of the attributes I used
PROCESSED_DEFAULTS = {
resolution: '500x400',
preserve_aspect_ratio: :height.
video_codec: 'libx264', # H.264/MPEG-4 AVC video codec
constant_rate_factor: '30', # GOP Size
frame_rate: '25', # frame rate
audio_codec: 'aac', # AAC audio codec
audio_bitrate: '64k', # Audio bitrate
audio_sample_rate: '44100' # Audio sampling frequency
}
When I am digging the issue, I found out that all this process happen from library called “FFMPEG”. And it is embedded with carrierwave:video gem to perform those video process features.
What is FFMPEG ?
A complete, cross-platform solution to record, convert and stream audio and video.
Check more info on the link below
Install FFMPEG using following commands.. ( Ubuntu )
sudo apt-get update
sudo apt-get install ffmpeg
if you want to check the installation got scceeded.
ffmpeg -version
This is my FFMPEG version
You can convert videos easily using the following commands once you successfully installed FFMPEG.
ffmpeg -i some-video.mp4 -filter:v "scale='min(640,iw)':min'(480,ih)':force_original_aspect_ratio=decrease,pad=640:480:(ow-iw)/2:(oh-ih)/2" output.mp4
All the encoding attributes can be given between the input video and the output video. like below
"scale='min(640,iw)':min'(480,ih)':force_original_aspect_ratio=decrease,pad=640:480:(ow-iw)/2:(oh-ih)/2"
Anyway, I tried this and The console looks like this.
When I convert the video got stretched from Carrierwave using FFMPEG only it worked fine. All were good.
So… What went wrong here with carrierwave gem.
Instead of finding the issue with carrierwave gem I added FFMPEG inside the class and used those methods.
What I did to fix the issue
I called a different method to encode the video instead of the encoding mechanism in the carrierwave.
version :rescaled do
process :encode
end
And the ENCODE method will create ffmpeg video object and do the transcode.
This would override the processes from carrierwave and do the encoding with the ffmpeg
Don’t forget to incldue the ffmpeg library on top of the class
require 'streamio-ffmpeg'
That’s all then…
Please mention other solutions if you found any.
Happy Coding :)