Video Upload/Processing with Ruby on Rails

ADMAT Bandara
4 min readJun 4, 2019

--

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

  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 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,

basic architecture for the video upload process

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.

Correctly encoded video

But…. Once a video uploaded form Android device, the re-scaled video looks like this, ( after encoding the video )

vertically pressed 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 :)

--

--