FFMPEG with Rails 4.2 in production - ruby-on-rails

I'm using FFMPEG to convert an uploaded wav file in a mp3.
My code works in development mode but not in production and I can't find where the error is. As far as I can tell, I think it's a path problem with the tmp file. FFMPEG works in production (Digital Ocean) when I run a command on the terminal.
My mp3 job:
class Mp3UploadJob < Struct.new(:audiofile_id)
def perform
path = audiofile.wav_file.url.to_s
mp3_file = File.join(Rails.root, "tmp", "uploads", "#{audiofile.filename}.mp3")
%x[ffmpeg -i "#{path}" -b:a 192k -ar 44100 -metadata title="#{audiofile.title}" -metadata artist="#{audiofile.mp3_artist_name}" -metadata album="#{audiofile.mp3_album}" -metadata date="#{audiofile.release_date}" -metadata genre="#{audiofile.genre}" "#{mp3_file}"]
audiofile.mp3_file = open(mp3_file)
audiofile.save!
File.delete(mp3_file)
end
end
Note: the wav file comes from a dropbox chooser box.
My wav job (ran before the mp3 job):
class WavUploadJob < Struct.new(:audiofile_id)
def perform
audiofile.remote_wav_file_url = audiofile.dropbox_wav
audiofile.save!
end
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

Native iOS video player fails on HLS encrypted with openssl

I'm having an issue with encrypting HLS using openssl. As described here: Using openssl encryption for Apple's HTTP Live Streaming I'm using following script to encrypt TS files created by ffmpeg:
encyptionKeyFile="crypt.key"
openssl rand 16 > $encyptionKeyFile
encryptionKey=`cat $encyptionKeyFile | hexdump -e '16/1 "%02x"'`
splitFilePrefix="$fileName.split."
encryptedSplitFilePrefix="${splitFilePrefix}enc."
numberOfTsFiles=`ls ${splitFilePrefix}*.ts | wc -l`
for i in {0..$numberOfTsFiles}; do
initializationVector=`printf '%032x' $i`
openssl aes-128-cbc -e -in ${splitFilePrefix}$i.ts -out ${encryptedSplitFilePrefix}$i.ts -nosalt -iv $initializationVector -K $encryptionKey
rm ${splitFilePrefix}$i.ts
done
ffmpeg command used to generate TS file is following:
ffmpeg -i $file -codec copy -map 0 -f segment -vbsf h264_mp4toannexb -segment_list $mainPlaylistName -segment_time 10 ${splitFilePrefix}%d.ts
M3U8 playlist file looks like:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-KEY:METHOD=AES-128,URI=crypt.key
#EXT-X-TARGETDURATION:19
#EXTINF:11.875000,
BigBuckBunnyMovie.split.enc.0.ts
#EXTINF:11.166667,
BigBuckBunnyMovie.split.enc.1.ts
#EXTINF:12.500000,
BigBuckBunnyMovie.split.enc.2.ts
#EXTINF:12.166667,
BigBuckBunnyMovie.split.enc.3.ts
#EXTINF:8.375000,
...
#EXT-X-ENDLIST
I thought that it might be a problem with encoding or something with ffmpeg command format but the thing is that encrypted stream doesn't work on native iOS player (MPMoviePlayerController) but works fine on VLC. What is more, unencrypted stream (using TS files produced by ffmpeg) works on both native player and VLC!
Can you suggest me what can I do to be able to play it on native iOS video player?
Thanks for all your responses!
The draft spec states that the URI value is a quoted string. See section 3.4.4 of the draft spec.

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

Prevent ffmpeg from taking over stdout

When I do system "ffmpeg -i just-do-it.mp4 -ab 96k -ar 22050 -qscale 6 output.flv" ffmpeg takes over the ruby process till the job is done, which sometimes take a long time. I've tried using threads amd fork in Ruby to no avail, also system equivalent commands like exec %x[] I also tried the latest Fibers in ruby 1.9.2, but I don't think I'm using it properly.
My question is how to run two ffmpeg processes from ruby concurrently?
EDIT:
fork do
fork do
system "ffmpeg -i you-know.mp4 -ab 96k -ar 22050 -qscale 6 #{Time.now.sec}.flv"
end
fork do
system "ffmpeg -i bangbang.mp4 -ab 96k -ar 22050 -qscale 6 #{Time.now.sec}.flv"
end
end
fork/exec is the right solution. Since forked processes inherit the parent processes fopen file handles/etc., you'll have to close (or redirect) the file handles you don't want children processes to use.
For example:
# this will print nothing, but yes is running as a forked process
# you'll want to `killall yes` after running this script.
fork do
[$stdout, $stderr].each { |fh| fh.reopen File.open("/dev/null", "w") }
exec "yes"
end
Ok, some comments on the code you posted. The outer fork is pointless. Just fork the two ffmpeg process from the main process. Maybe write a helper function like:
def ffmpeg(mp4)
fork do
[$stdout, $stderr].each { ... }
exec "ffmpeg -i #{mp4} ..."
end
end
ffmpeg("you-know.mp4")
ffmpeg("bangbang.mp4")
Try the subprocess gem - that's what I'm using now for dealing with process forking and finding it much easier to use.
E.g.
work_list.each do |cmd|
process = Subprocess::Popen.new(cmd)
process.run
process.wait
#puts process.stdout
#puts process.stderr
puts process.status
end

converting video files to .flv format in grails

I am developing a web-application in grails.In that I have implemented video's playing option.For playing video I used the flashplayer plugin .It is working.Now I am planning to implement the feature that user's also can upload their video's.After uploading the video files how to convert those video files to .flv format?
or
Does flash player plays all the video formats?I tried with .wmv file .It is not working.
Can anyone provide help on this?
Thanks
Flash can only play FLVs, and h.264 encoded videos (e.g. mp4, f4v). You can convert video into any of these formats using FFmpeg. If you're using Windows, you can get some pre-built binaries here.
Sample command-line that should convert inputfile.avi to an flv with an audio bitrate of 48kbps, and a video bitrate of 224kbps (might need to substitute libmp3lame for mp3 depending on version of ffmpeg):
ffmpeg -i inputfile.avi -s 640x480 -y -f flv -acodec mp3 -ac 1 -ab 48k -b 224k -ar 22050 outputfile.flv
Sample for h.264 / aac:
ffmpeg -i inputfile.avi -s 640x480 -y -f mp4 -vcodec libx264 -acodec libfaac -ab 48k -b 224k -ar 22050 outputfile.mp4

Resources