FFMPEG, how to name the output file at my convenience? - ruby-on-rails

I have here a script that allows me to compress all .mp4 files of a folder.
The output file is:
original_name.mp4.webm
I would like the output file to be original_name.webm.
How to get rid of .mp4?
I think I have to learn .gsub(/ /, '\ ').
Please suggest.

I found it sorry for the buzz, here is the final code that removes ".mp4" and rename it ".webm"
Dir.glob("*.mp4") do |my_text_file|
puts ' --> converting: ' + my_text_file
puts "ffmpeg -i #{my_text_file.gsub(/ /, '\ ')} -b:v 640k #{my_text_file.gsub(/.mp4/, '')}.webm"
`ffmpeg -i #{my_text_file.gsub(/ /, '\ ')} -b:v 640k #{my_text_file.gsub(/.mp4/, '')}.webm`
end

Related

Convert WAV into MP3 using FFMPG with the carrier_wave gem

Inside my "wave_uploader.rb" script I have the following code:
class PictureUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
include CarrierWave::MimeTypes
version :wav do
process :convert_to_mp3
def convert_to_mp3
temp_path = Tempfile.new([File.basename(current_path), '.mp3']).path
`ffmpeg -t 15 -i #{current_path} -acodec libmp3lame -f mp3 #{temp_path}`
File.unlink(current_path)
FileUtils.mv(temp_path, current_path)
end
def full_filename(for_file)
super.chomp(File.extname(super)) + '.mp3'
end
end
I am trying to convert the WAV file into a 20 second MP3 file and delete the WAV file once it is converted. The code above runs but I can't find the converted MP3 file so I am guessing it did not work correctly.
At the end of wave_uploader.rb I have code that returns the unique name once it is processed but I commented out the code out thinking the code below was causing the WAV file not to be converted to an MP3.
# def filename
# "#{secure_token}.#{file.extension}" if original_filename.present?
# end
# def secure_token
# var = :"##{mounted_as}_secure_token"
# model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid)
end
Any help would be greatly appreciated on how to get this working right.
One thing I see is:
`ffmpeg -t 15 -i #{current_path} -acodec libmp3lame -f mp3 #{temp_path}`
If ffmpeg is not in your path then the OS won't be able to find it, and will return an error, however, because you're using backticks, the OS can't return a string from STDERR, which is where the error would be displayed. Backticks only return STDOUT.
To debug this try this from the command-line:
which ffmpeg
If ffmpeg is found, instead of:
`ffmpeg -t 15 -i #{current_path} -acodec libmp3lame -f mp3 #{temp_path}`
Try:
puts `which ffmpeg`
and see what is output.
I suspect it's not in your path, so you'll have to locate where it is and provide the full path to where it is on disk.
Also, it's better to move the original file, move the new file to the original file's name, then delete the original or leave it as a ".bak" file. That way the original is kept until all the code has processed:
FileUtils.mv(current_path, current_path + '.bak')
FileUtils.mv(temp_path, current_path)
File.unlink(current_path + '.bak') # <-- optional

Ignoring directories from a file

I am in the process of creating a script that lists all files opened via lsof output. I would like to checksum specific files and ignore directories from that output but am at a loss to do so EFFECTIVELY. For example: (I'm using FreeBSD btw)
lsof | awk '/\//{print $9}' | sort -u | head -n 5
prints:
/
/bin/sleep
/dev/bpf
What I'd like to do is: FROM that output, ignore any directories and perform an md5 on FILES (not directories).
Any pointers?
Give a try to following perl command:
lsof | perl -MDigest::MD5=md5_hex -ane '
$f = $F[ $#F ];
-f $f and printf qq|%s %s\n|, $f, md5_hex( $f )
'
It filters lsof output to plain files (-f). Take a look into perlfunc to change it to add different kind of files.
It outputs each file and its md5 separated by a space character. An example in my system is like:
/usr/lib/libm-2.17.so a2d3b2de9a1f59fb99427714fefb49ca
/usr/lib/libdl-2.17.so d74d8ac16c2d13128964353d4be7061a
/usr/lib/libnsl-2.17.so 34b6909ec60c337c21b044642b9baa3d
/usr/lib/ld-2.17.so 3d0e7b5b5c4e59c5c4b6a858cc79fcf1
/usr/sbin/lsof b9b8fbc8f296e47969713f6369d97c0d
/usr/lib/locale/locale-archive 3ea56273193198a718b9a5de33d553db
/usr/lib/libc-2.17.so ba51eeb4025b7f5d7f400f1968f4b5f9
/usr/lib/ld-2.17.so 3d0e7b5b5c4e59c5c4b6a858cc79fcf1
...

save FFMPEG screenshot output file to variable

How can i get the output file of this FFMPEG code saved to a variable?
def take_screenshot
logger.debug "Trying to grab a screenshot from #{self.file}"
system "ffmpeg -i #{self.file} -ss 00:00:02 -vframes 1 #{Rails.root}/public/uploads/tmp/screenshots/#{File.basename(self.file)}.jpg"
self.save!
end
I have tried:
self.screenshot = system "ffmpeg -i #{self.file} -ss 00:00:02 -vframes 1 #{Rails.root}/public/uploads/tmp/screenshots/#{File.basename(self.file)}.jpg"
but this doesn't save anything.
thanks in advance!
ffmpeg usually outputs nothing on stdout and all of its debug messages on stderr. You can make it output the video (or image) to stdout when you pass - as the output file. You'd then also need to suppress stderr.
system "ffmpeg -i #{self.file} -ss 00:00:02 -c:v mjpeg -f mjpeg -vframes 1 - 2>/dev/null"
This will output the raw data of the JPEG-encoded image to stdout. From there you can save the data to a variable and, for example, transfer it somewhere else.
To get stdout from system calls, see here: Getting output of system() calls in ruby – especially popen3 should help you in that case, where you could discard the stderr from within Ruby.

How can I send grep results into a different output file for each input file?

I have a folder that contains text files. I need to extract lines that has 'BA' from these text files . I used grep command to print the lines with BA. I would like to save the outputs to another folder with the same file names. How can I change the following code?
grep " BA " dir/*.txt
for i in dir/*.txt; do
grep " BA " $i > $newdir/`basename $i`
done
Note the use of basename, which takes dir/a.txt (say) and returns a.txt
Sounds like a job for GNU parallel:
parallel --dry-run grep '" BA "' '{} > otherdir/{/}' ::: dir/{a,b,c}.txt
Output:
grep " BA " dir/a.txt > otherdir/a.txt
grep " BA " dir/b.txt > otherdir/b.txt
grep " BA " dir/c.txt > otherdir/c.txt
Remove --dry-run when you're happy with what you see.
{} is replaced by the inputs after ::: (these can also come from stdin or a file), {/} is the basename of {}.

cron job is not completing the process?

I have a ruby program to convert video to MP4 format using ffmpeg. And I'm using the crontab to run the ruby program every 15 minutes. crontab actually runs the ruby program, but the conversion of the file is not complete. The process is stopped before completing the conversion. My sample code for testin is below.
def convert(y)
system "ffmpeg -i #{SOURCE_FOLDER + LOCATION_SOURCE}/#{y} -acodec libfaac -ar 44100 -ab 96k -vcodec libx264 #{DEST_FOLDER + LOCATION_DEST}/#{y}"
end
SOURCE_FOLDER = "/home/someone/work/videoapp/public/"
DEST_FOLDER = "/home/someone/work/videoapp/public/"
LOCATION_SOURCE = "source"
LOCATION_DEST = "dest"
files = Dir.new(SOURCE_FOLDER + LOCATION_SOURCE)
files.each do |x|
convert(x)
end
This code works fine, if i run it manually in the console.
My first guess is that it's dying on "dot" directories. In Unix there are two directories in every directory/folder: "." and "..". You'll either need to specifically skip those in your script:
next if File.directory?(x) # OR
next file x.match(/^\.+$/)
-- OR --
Look specifically for whatever filetypes you are wanting
Dir[SOURCE_FOLDER + LOCATION_SOURCE + "*.wav"].each do |file|
convert(file)
end
Update: 20110401
Add Unix redirects to the crontab entry to see what the output is
* * * * * /your/program/location/file.rb 1> /some/output/file.txt 2>&1

Resources