Convert .mov files to .mp4 using FFMPEG with heroku and rails 7

Convert .mov files to .mp4 using FFMPEG with heroku and rails 7

Dhaval Baldha

21 Sep 2023

10 MINUTES READ

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

In buildpacks file

heroku-buildpack-ffmpeg-latest

heroku-buildpack-ruby

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
  1. 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.
  2. Inside the video player block, it defines an array ‘video_formats’ containing the supported video formats(mp4 and mov)
  3. 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.
      


Dhaval Baldha
Dhaval Baldha

Co-founder

Dhaval is a visionary leader driving technological innovation and excellence. With a keen strategic mindset and deep industry expertise, he propels the company towards new heights. His leadership and passion for technology make him a cornerstone of Techvoot Solutions' success.

Linkedin
Hire Skilled Developer

*Please fill all the required fields

Get our Newsletter

Customized solutions for your projects

*Please fill all the required fields