What options I should use to rescale video without skewing them in FFMPEG Rails? - ruby-on-rails

The main issue happens when it processes the recalling
All videos uploading from Apple iOS will process nicely.
But all videos uploading from Android devices are getting skewed.
In my rails app, I am using Carrierwave:Video and FFMPEG to process videos with the help of delayed jobs.
class VideoUploader < CarrierWave::Uploader::Base
include CarrierWave::Video
include CarrierWave::Video::Thumbnailer
# For carrierwave_backgrounder
include ::CarrierWave::Backgrounder::Delay
version :rescaled do
process encode_video: [
:mp4,
resolution: "640x480", # Aspect ratio is preserved automatically
audio_codec: "aac",
custom: "-strict experimental -q:v 0 -preset slow -g 30",
callbacks: { after_transcode: :set_success }
]
end
version :thumb do
process thumbnail: [{format: 'png', quality: 10, size: 400, strip: true, logger: Rails.logger}]
def full_filename for_file
png_name for_file, version_name
end
end
This is correct videos screenshot
https://drive.google.com/open?id=1D0aNWcVxtL6DbTwBmWWIGzUUuyEyWNOG
This the video screenshot after video process with FFMPEG
https://drive.google.com/open?id=1vilExHoan2UuRPH9RbiZig58H1TwyewA
(It's like vertically pressed)
Please help me, if you know a solution

Finally, I found a solution and here it is...
I required the FFMPEG library separately in the class.
require 'streamio-ffmpeg'
And the called custom function to do the encoding work.
version :rescaled do
process :encode
end
And the ENCODE method will create ffmpeg video object and do the transcode.
def encode
movie = ::FFMPEG::Movie.new(current_path)
tmp_path = File.join( File.dirname(current_path), "tmpfile.mp4" )
options = "[define the options you want]"
movie.transcode(tmp_path, options)
File.rename tmp_path, current_path
end
This would override the processes from carrierwave and do the encoding with the ffmpeg
That’s all then…
Please mention other solutions if you found any.
Thanks...
Please refer my article for more info:
Article about this issue and it's background

Related

Rails Api Save MiniMagick Image to Active Storage

I'm using MiniMagick to resize my image. My method looks something like that:
def resize
mini_img = MiniMagick::Image.new(img.tempfile.path)
mini_img.combine_options do |c|
c.resize '50x50^'
c.gravity 'center'
c.extent '50x50'
end
mini_img
end
Resize works, but the problem is when I try save mini_img to Active Storage, because I get error Could not find or build blob: expected attachable, got #<MiniMagick::Image. Can I somehow convert MiniMagick::Image (mini_img) to normal image and save it into Active Storage?
Yes, you can. Currently you are trying to save an instance of MiniMagick::Image to ActiveStorage, and that's why you receive that error. Instead you should attach the :io directly to ActiveStorage.
Using your example, if you wanted to attach mini_img to a hypothetical User, that's how you would do it:
User.first.attach io: StringIO.open(mini_img.to_blob), filename: "filename.extension"
In this example I am calling to_blob on mini_img, which is an instance of MiniMagick::Image, and passing it as argument to StringIO#open. Make sure to include the :filename option when attaching to ActiveStorage this way.
EXTRA
Since you already have the content_type when using MiniMagick you might want to provide it to ActiveStorage directly.
metadata = mini_img.data
User.first.attach io: StringIO.open(mini_img.to_blob), filename: metadata["baseName"], content_type: metadata["mimeType"], identify: false
For someone who will have a similar problem. I just changed method to:
def resize
MiniMagick::Image.new(img.tempfile.path).combine_options do |c|
c.resize '50x50^'
c.gravity 'center'
c.extent '50x50'
end
img
end
In this solution, MiniMagick only resized the photo and did nothing else with it, so I didn't have to convert it again.

Carrierwave MiniMagick PDF Preview

Uploading files in my Rails app via Carrierwave / MiniMagick. Trying to create previews of the first page of PDFs. Ran into a few issues:
1) Some PDFs convert but the background is all black. Images and comments are visible
2) Some PDFs result in this error:
ImageProcessing::Error - Source format is multi-layer, but destination format is single-layer. If you care only about the first layer, add `.loader(page: 0)` to your pipeline. If you want to process each layer, see https://github.com/janko/image_processing/wiki/Splitting-a-PDF-into-multiple-images or use `.saver(allow_splitting: true)`.:
My codes looks like this:
version :thumb do
process :convert => 'jpg'
process :resize_to_limit => [50, 50]
def full_filename (for_file = model.file.file)
"preview_thumb.jpg"
end
end
Not clearly understanding which MiniMagick command line arg to add and how to add them.

Carrierwave: convert an uploaded PNG to JPG by replacing the original version (or: having versions with a different file format than original file)

I have the following model:
class ScreenshotUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
convert :jpg
version :thumb do
process resize_to_fill: [50, 50]
end
def extension_whitelist
%w(jpg jpeg gif png)
end
version :print do
process border: ['black']
process quality: 80
end
end
The upload of the image happens via pasting an image from the clipboard via https://github.com/layerssss/paste.js and is saved as a base64 encoded string into a <textarea>, then uploaded using the https://github.com/y9v/carrierwave-base64 gem:
class Finding < ApplicationRecord
mount_base64_uploader :screenshot, ScreenshotUploader
end
In the HTML form, it looks like this:
After uploading, the result is the following files:
screenshot.png it's a PNG, not a JPG!
thumb_screenshot.jpg
print_screenshot.jpg
But I need the original file to be also converted to JPG, as I need to save disk space. How can I achieve this?
You can do it like it written on the carrier wave documentation
Just replace system("mogrify -resize '1200\>' #{file.file}") with system("mogrify -format jpg #{file.file}") and then remove original file.
Adding to Vasiliy's answer, I came up with the following:
after :store, :convert_original_to_jpg
def convert_original_to_jpg(new_file)
if version_name.nil?
system("mogrify -format jpg -quality 80 #{file.file}")
system("unlink #{file.file}") # Remove the old PNG file
model.update_column mounted_as, "#{mounted_as}.jpg" # The filename in the DB also needs to be manually set to .jpg!
end
end
While this works for creating the file, it does not when updating the file, as the new_file parameter then is nil, and thus all images are removed.
I think this is some quirk that has to do with the carrierwave-base64 gem, and I don't have any motivation to dig into this any further. So the proposed solution might not be too useful, but for the sake of documentation I wanted to post it here.
In my special case, I decided to let go of the idea of saving disk space by converting PNG to JPG. Instead, I simply set process quality: 80 to save at least some space on the versions.
For the original PNG (which is saved in lossless state by carrierwave-base64 gem), I simply use the following code to shrink its quality:
after :store, :optimise_images
def optimise_images(new_file)
return if Rails.env.test? # Optimising consumes quite some time, so let's disable it for tests
if version_name.nil?
image_optim = ImageOptim.new pngout: false,
svgo: false,
pngcrush: false,
optipng: false,
pngquant: {allow_lossy: true}, # Everything disabled except pngquant, to keep the performance at a good level
advpng: false
image_optim.optimize_images!(Dir["#{File.dirname(file.file)}/*.png"])
end
end

Rails: Paperclip produces different results for similar videos

I am using the Paperclip Gem to handle video uploads on my Rails app. I've followed the instructions in a few other stackoverflow questions and external tutorials to get video uploads working. However, currently there is a strange glitch with the system that I don't understand.
When uploading two different videos, the app will be able to show a thumbnail and no video for one upload, and no thumbnail but video for another one.
Both videos use the same codecs, are around the same length, but are a bit different in their dimensions & file size.
When I upload them, test1 has a thumbnail, but my browser will not load the video file. It exists in my file system but Chrome will not play it.
The opposite happens for test2. Its thumbnail in my file system is zero bytes, but the video loads fine in my browser.
Here are the paperclip upload parameters for my object:
has_attached_file :video, :styles => {
:medium => { :format => 'mp4' },
:thumb => { :geometry => "500x500#", :format => 'jpg', :time => 10 }
}, :processors => [:transcoder]
validates_attachment_presence :video
validates_attachment :video, content_type: { content_type: ["video/mp4", "video/mov", "video/wav", "video/wmv"] }
I've created a Github repo with an example app that reproduces the issue, at least on my system.
The issue is in: :time => 10 parameter
Change it on: :time => 1
This change means: create screenshot on 1st second instead of 10th second. Because the second movie has only 10 second length, during the first movie has 12 seconds length. Thus the first movie has screenshot, and second don't and uses previous one.
Wish it helped you!
I was able to play both files in multiple browsers without issue.
However, the reasons why test1.mp4 might not (seem) to work are:
test1.mp4 has the moov atom at the end of the file:
AtomicParsley test1.mp4 -T
Atom ftyp # 0 of size: 32, ends # 32
Atom free # 32 of size: 8, ends # 40
Atom mdat # 40 of size: 1310866, ends # 1310906
Atom moov # 1310906 of size: 9926, ends # 1320832
This means the browser must fully download the file before it can play it. If you're on a slow connection it might take a while and appear like it's not working.
test2.mp4 has the moov atom at the beginning of the file meaning it can be played back before the download finishes:
AtomicParsley test2.mp4 -T
Atom ftyp # 0 of size: 32, ends # 32
Atom moov # 32 of size: 7464, ends # 7496
You can move the moov atom to the beginning of the file using the ffmpeg movflags faststart option or with the qt-faststart tool.
It shouldn't be an issue if you're using your local file system, so see below.
test1.mp4 uses the Main H.264 profile while test2.mp4 uses the Constrained Baseline profile. This can be an issue on some mobile devices as the Baseline profile has the most support. However it shouldn't be an issue with newer devices.
You could try to re-encode it with the Baseline profile to see if this is the issue.
Please do follow this link https://github.com/thoughtbot/paperclip/wiki/Thumbnail-Generation
and i think validation for video can be done in this way:
validates_attachment :video, :presence => true
rather than doing with presence and again without it.
For image i followed :
validates_attachment :attachment, content_type: { content_type: ["image/jpeg", "image/gif", "image/png"] }
Hope this will work for you :-)

How to place text on image

Is there a way to place text on image in Rails? I am using Carrierwave for image upload, but I don't think it supports watermarking.
I tried attaching image watermark and made it work but can't figure out how to watermark with text.
For example, this is good way to place image watermark.
This is the code that I user to put watermarks on a image I am sure that you can change it a bit to make it your own. Also make sure that you have Magick turned on.
Take a look at carrierwave-add-a-watermark-to-processed-images its similar
# Process files as they are uploaded:
process :resize_to_fill => [850, 315]
process :convert => 'png'
process :watermark
def watermark
manipulate! do |img|
logo = Magick::Image.read("#{Rails.root}/app/assets/images/watermark.png").first
img = img.composite(logo, Magick::NorthWestGravity, 15, 0, Magick::OverCompositeOp)
end
end

Resources