Table of Contents
Introduction
I’m encountering a problem where specific browsers do not support the QuickTime Video format.
The code seems to be well-organized and follows a clear flow for handling the conversion and processing of MOV files.
To Implement video or image uploads with FFMPEG using CarrierWave and Heroku in Rails 7, you will first need to ensure that the necessary gems are properly installed and configured. This includes CarrierWave, FFMPEG, and any other required libraries.
FFMPEG setup
Ensure FFMPEG is installed in your local system.
sudo apt-get install ffmpeg
Check this ffmpeg -v and which ffmpeg
techvoot@office ~/rails/snap-demo (tv-master) $ ffmpeg -v
ffmpeg version 4.4.2-0ubuntu0.22.04.1 Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 11 (Ubuntu 11.2.0-19ubuntu1)
configuration: --prefix=/usr --extra-version=0ubuntu0.22.04.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-pocketsphinx --enable-librsvg --enable-libmfx --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
libavutil 56. 70.100 / 56. 70.100
libavcodec 58.134.100 / 58.134.100
libavformat 58. 76.100 / 58. 76.100
libavdevice 58. 13.100 / 58. 13.100
libavfilter 7.110.100 / 7.110.100
libswscale 5. 9.100 / 5. 9.100
libswresample 3. 9.100 / 3. 9.100
libpostproc 55. 9.100 / 55. 9.100
techvoot@office ~/rails/snap-demo (tv-master) $ which ffmpeg
/usr/bin/ffmpeg
For Heroku, create a ‘buildpacks’
file with the following content. The root folder of your project dir creates a buildpacks File(project_name)/.buildpacks
In buildpacks file
Convert .mov to .mp4
require 'streamio-ffmpeg'
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
if Rails.env.development?
storage :file
else
storage :fog
end
def store_dir
"uploads/snap_datum/#{model.id}"
end
def extension_allowlist
%w(jpg jpeg png mp4 mov)
end
def convert_to_mp4
if file.extension == 'mov'
Rails.logger.info("Converting #{file.filename} to MP4...")
cache_stored_file! if !cached?
video = FFMPEG::Movie.new(file.path)
tmp_path = File.join(File.dirname(current_path), "tmpfile.mp4")
begin
Rails.logger.info("Transcoding video...") video.transcode(tmp_path,%w(-threads 2 -c:v libx264 -crf 19 -preset ultrafast -c:a aac -strict experimental -b:a 192k -ac 2))
file.content_type = 'video/mp4'
File.rename(tmp_path, current_path)
Rails.logger.info("Conversion of #{file.filename} to MP4 is complete.")
rescue => e
Rails.logger.error("Error converting #{file.filename} to MP4: #{e.message}")
end
end
end
# Process the uploaded video (only for .mov files)
process :convert_to_mp4, if: :mov?
# Check if the uploaded file is a .mov file
def mov?(new_file)
new_file.extension.include? 'mov'
end
# Override the filename to use .mp4 extension for the converted video
def filename
if original_filename.present?
is_mov_file? ? "#{secure_token}.mp4" : original_filename
end
end
def is_mov_file?
file.extension == 'mov'
end
# Add a unique token to the filename to avoid overwriting
def secure_token
var = :"@#{mounted_as}_secure_token"
model.instance_variable_get(var) or
model.instance_variable_set(var, SecureRandom.uuid)
end
end
- Convert_to_mp4 method: Navigate to your newly created Storage Account.
- Process: convert_to_mp4, if: :mov? This line specifies the convert_to_mp4 method Should be automatically triggered during the upload process if the uploaded file is a .mov file. This happens through the process directive
- .mov?(new_file) method: This method checks whether the given new_file has a .mov extension. It it returns true if the extension includes “mov” and false otherwise.
- Filename method: This method determines the filename for the stored file. If the original filename is present and the file is a .mov file (as determined by is_mov_file?) It renames the file with a unique secure token and a .mp4 extension.
- Is_mov_file? method: This method check if the current file being processed has the extension .mov.
- Secure_token method: This method generates a unique secure token for the filename. It uses the SecureRandom.uuid method to create a Universal Unique Identifier and store it as an instance variable on the model. This helps to ensure that filenames are unique and prevents overwriting the files.
My Index view file
<%= link_to admin_snap_path(snap) do %>
<%= video_tag snap_datum&.path&.url, controls: true,
class: "w-100" if snap_datum.path.present? do %>
<% video_formats = ['mp4', 'mov'] %>
<% video_formats.each do |format| %>
<%= video_source_tag snap_datum&.path&.url(format),
type: "video/#{format}" %>
<% end %>
<% end %>
<% end %>
Here’s what this code does step by step
- Inside the link, it generates a video player using the ‘video_tag’ helper. The ‘video_tag’ helper creates an HTML5 video player element.
- ‘snap_datum.path.url‘ is used as the video source URL.
- controls: true add playbacks controls(play, pause,volume, etc) to the video player.
- Inside the video player block, it defines an array ‘video_formats’ containing the supported video formats(mp4 and mov)
- For each format, it generates a tag using the ‘video_source_tag’ helper. each tag specific to the video source URL with the format extension and the MIME type.
In summary, this code generated an HTML video player with support for multiple video formats (MP4 to MOV) and added playback controls. It also checks if there’s a video source to avoid rendering an empty video player. The player-wrapped link that points to admin_snap_path for a ‘snap’ object.
Converting file_example_MOV_480_700kB.mov to MP4...
Transcoding video...
I, [2023-09-21T15:47:13.935923 #9118] INFO -- : Running transcoding...
["/usr/bin/ffmpeg", "-y", "-i", "/home/techvoot/rails/snap-demo/tmp/1695291433-622229266918752-0001-7269/file_example_MOV_480_700kB.mov", "-threads", "2", "-c:v", "libx264", "-crf", "19", "-preset", "ultrafast", "-c:a", "aac", "-strict", "experimental", "-b:a", "192k", "-ac", "2", "/home/techvoot/rails/snap-demo/tmp/1695291433-622229266918752-0001-7269/tmpfile.mp4"]
I, [2023-09-21T15:47:14.340725 #9118] INFO -- : Transcoding of /home/techvoot/rails/snap-demo/tmp/1695291433-622229266918752-0001-7269/file_example_MOV_480_700kB.mov to /home/techvoot/rails/snap-demo/tmp/1695291433-622229266918752-0001-7269/tmpfile.mp4 succeeded
Conversion of file_example_MOV_480_700kB.mov to MP4 is complete.