Question

I'm having issues uploading portrait videos using the Carrierwave-Video gem. When portrait videos are uploaded (particularly video captured on mobile devices), they are rotated 90 degrees clockwise. In the Carrierwave-Video documentation, there's an option for dynamic configuration, but I don't see a way to dynamically pass custom parameters for transcoding the video based on video orientation. I know that if I run the following line, I'm able to rotate the video 90 degrees CCW:

encode_video(:mp4, custom: "-vf transpose=1")

but I need a reliable way to detect whether the video needs to be rotated or not. I was wondering if there was some way for me to run a conditional parameter with ffmpeg that only runs if the video is portrait.

In case it's helpful, this is what my Video Uploader looks like in my Rails app (for some reason, the transcoding process is being run even before it detects the orientation of the video):

require 'carrierwave/processing/mime_types'

class VideoPathUploader < CarrierWave::Uploader::Base

  include CarrierWave::Video
  include CarrierWave::Video::Thumbnailer
  include CarrierWave::MimeTypes

 process :encode

def encode
    Rails.logger.debug "in encode"
    video = FFMPEG::Movie.new(@file.path)
    video_width = video.width
    video_height = video.height
    Rails.logger.debug "video widthxheight: #{video.width}x#{video.height}"
    aspect_ratio = video_width/video_height
    if video_height > video_width
      # rotate video
      Rails.logger.debug "portrait video"
      encode_video(:mp4, custom: "-vf transpose=1", aspect: aspect_ratio)
    else
      encode_video(:mp4, aspect: aspect_ratio)
    end

    instance_variable_set(:@content_type, "video/mp4")
    :set_content_type_mp4
  end
end
Was it helpful?

Solution

I was able to solve the problem by using the mini_exiftool gem. After installing exiftool on my computer (using brew install exiftool), I was able to get the orientation and aspect ratio of the uploaded video and use that to determine whether or not to apply a transform to the video using ffmpeg. Here is my final uploader:

require 'carrierwave/processing/mime_types'
require 'rubygems'
require 'mini_exiftool'

class VideoPathUploader < CarrierWave::Uploader::Base

 process :encode

 def encode
    video = MiniExiftool.new(@file.path)
    orientation = video.rotation

    if orientation == 90
      # rotate video
      Rails.logger.debug "portrait video"
      aspect_ratio = video.imageheight.to_f / video.imagewidth.to_f
      encode_video(:mp4, custom: "-vf transpose=1", aspect: aspect_ratio)
    else
      aspect_ratio = video.imagewidth.to_f / video.imageheight.to_f
      encode_video(:mp4, resolution: :same, aspect: aspect_ratio)
    end
    instance_variable_set(:@content_type, "video/mp4")
    :set_content_type_mp4
  end

end

Also, in case it's helpful, I also had to install exiftool on Heroku to use it with my Rails app. I did this by using the following buildpack:

https://github.com/benalavi/buildpack-exiftool

After installing the buildpack, I still had to manually specify the path for exiftool (it's supposed to do this automatically when it installs the buildpack, but it didn't do it for me). I did this by manually setting the path:

heroku config:set PATH=*all_your_other_paths*:vendor/exiftool-9.40/bin

OTHER TIPS

I had a similar issue and used a solution based my solution off of scientific's

You'll most likely want to clear out the rotation meta data associated with the video. Some players (quicktime) will look at the rotation meta data and rotate the video accordingly. So if you rotate 90 on transcoding and the video is then rotated 90 in the player, it will play at 180 degrees. I also added a few flags to increase the quality of the transcoded video.

if orientation == 90
  aspect_ratio = video.imageheight.to_f / video.imagewidth.to_f
  encode_video(:mp4, custom: "-qscale 0 -preset slow -g 30 -vf 'transpose=1' -metadata:s:v:0 rotate=0", aspect: aspect_ratio)
else
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top