This article is about an issue I struggled to solve for a long time. Iam 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 mediacontent 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:
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
<script src="https://gist.github.com/AsithaBandara/641e995f6a1bbc6afb70d4404108928b.js"></script>
Mounted Video Uploader from CarrierwaveVideo gem looks like this
view rawvideo_uploader.rb hostedwith ❤ by GitHub
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, there-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 usedare;
PROCESSED_DEFAULTS = {
resolution: '500x400',
preserve_aspect_ratio: :height.
video_codec: 'libx264', # H.264/MPEG-4 AVC videocodec
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
sudoapt-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 withcarrierwave 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.
view rawencode.rb hostedwith ❤ by GitHub
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 theclass.
require 'streamio-ffmpeg'
That’s all then. Please don't forget to mention any solutions you find any.