This article is about an issue I struggled to solve for a long time. I am pretty excited to share the solution with you.
Contents
1. Existing Architecture with Carrierwave GEM
2. The Issue I faced
3. What is FFMPEG?
4. 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”.
1. Raw video file
2. Scaled video file (less size, quality)
3. Thumbnail image
I managed to make this feature succesful 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
Actually, this works well. However, this is the problem I faced. Once a video is uploaded it should look like below.
Nevertheless, when the video is uploaded from an Android device, the re-scaled video looks like below (after encoding)
The video process (encoding) works nicely for the iOS-device-generated video, but not for the android generated ones. Even though I changed the encoding attributes it didn’t fix the problem. Some of the attributes I used are;
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 was digging in to this issue, I found out that this process happens from a 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 here.
Install FFMPEG using following commands (Ubuntu).
sudo apt-get update
sudo apt-get install ffmpeg
If you want to check it was a succesful installation
ffmpeg -version
This is my FFMPEG version
You can convert videos easily using the following commands once you successfully install FFMPEG.
ffmpeg -i some-video.mp4 -filter:v se,pad=640:480:(ow-iw)/2:(oh-ih)/2" output.mp4
All encoding attributes can be included between the input video and the output video, as below
"scale='min(640,iw)':min'(480,ih)':force_original_aspect_ratio=decrea se,pad=640:480:(ow-iw)/2:(oh-ih)/2"
When I tried this, the console looks like this.
When I converted the video, it was stretched. Only with Carrierwave using FFMPEG it worked fine. All were good. So, what went wrong here, was with carrierwave gem. However, instead of looking for 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 take care of 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 don't forget to mention any solutions you find any.
LEAVE A COMMENT