Skip to main content

A seamless viewing experience with Ruby on Rails

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.



06 / June / 2019 Ruby Asitha Bandara

LEAVE A COMMENT







POST COMMENTS


© 2019 Creative Software. All Rights Reserved | Privacy | Terms of Use