How do i make rails wait until an ffmpeg call is complete?

In my app i upload a file, convert it with ffmpeg, delete the original
and make a small thumbnail out of the big thumbnail ffmpeg makes.

At the moment it seems like these actions are tripping over each other -
how can i make the app wait until ffmpeg has completed it’s output
before doing the next thing?

On 18 Sep 2007, at 18:56, Max W. wrote:

In my app i upload a file, convert it with ffmpeg, delete the original
and make a small thumbnail out of the big thumbnail ffmpeg makes.

At the moment it seems like these actions are tripping over each
other -
how can i make the app wait until ffmpeg has completed it’s output
before doing the next thing?

Why don’t you consider the following setup:

  • Let the user upload the movie
  • Hand the movie over to Backgroundrb for processing and render a
    “Movie being processed”-message and a PeriodicalUpdater to your view
  • In the PeriodicalUpdater method, query Backgroundrb to see if the
    processing is finished
  • If it’s finished, render it in the page

This way, you’ll avoid locking up one of your mongrels during a
possible long running process (and movie processing tends to be a
long running process). On top of that, the user can continue working
with your application while the processing is taking place. It might
require you to rethink your interface a bit, but the user experience
will be substantially improved.

Best regards

Peter De Berdt

Peter De Berdt wrote:

On 18 Sep 2007, at 18:56, Max W. wrote:

Why don’t you consider the following setup:

  • Let the user upload the movie
  • Hand the movie over to Backgroundrb for processing and render a
    “Movie being processed”-message and a PeriodicalUpdater to your view
  • In the PeriodicalUpdater method, query Backgroundrb to see if the
    processing is finished
  • If it’s finished, render it in the page

Best regards

Peter De Berdt

That sounds like it might be a nice idea, but i don’t really have time
to do anything as nice as that at the moment - i just need a simple way
to make the program wait…

Could you post your code, as far as I know, the ´ffmpeg xxxxx´calls
from ruby execute synchronically, so it should wait before going
further.

On 18 Sep 2007, at 19:32, Max W. wrote:

That sounds like it might be a nice idea, but i don’t really have time
to do anything as nice as that at the moment - i just need a simple
way
to make the program wait…

Best regards

Peter De Berdt

Peter De Berdt wrote:

Could you post your code, as far as I know, the ´ffmpeg xxxxx´calls
from ruby execute synchronically, so it should wait before going
further.

On 18 Sep 2007, at 19:32, Max W. wrote:

That sounds like it might be a nice idea, but i don’t really have time
to do anything as nice as that at the moment - i just need a simple
way
to make the program wait…

Best regards

Peter De Berdt

Funny you should say that, i just discovered i was passing an option
that told it to only do the first second!

Basically i am an idiot…

Thanks for your advice!

I’d be interested in seeing your code. Is it available?

On Sep 18, 9:56 am, Max W. [email protected]

On 19 Sep 2007, at 10:24, Max W. wrote:

Sure - here’s my method, i’m currently passing it this value for
‘command’, generated from some other methods. Previously i had “-t
001”
as well which was the real reason my movies were truncated - that says
“only do the first second”: with that dodgy option removed, it works
fine. I’d still be interested in advice for taking the standard
output
progress report in the method and using it to inform the user of
progress, though. And how to tell the user about uploading progress?
(uploading is slower than the conversion)

Upload progress: use one of the many “ajax upload solutions” out
there. I really like SWFUpload, because it’s the Flash file that
streams the upload to the server that keeps track of the upload
progress. Other solutions mostly rely on serverside tracking.

For the progress report on the conversion, your method makes it
impossible, because Rails can only return information at the end of
the request and your method only completes after the conversion. The
only way to accomplish what you’re looking for, is passing the rails
request on to backgroundrb, and use a PeriodicalUpdater (or some push
technology, but that’s even more complex) to query the backgroundrb
worker.

Best regards

Peter De Berdt

eggie5 wrote:

I’d be interested in seeing your code. Is it available?

On Sep 18, 9:56 am, Max W. [email protected]

Sure - here’s my method, i’m currently passing it this value for
‘command’, generated from some other methods. Previously i had “-t 001”
as well which was the real reason my movies were truncated - that says
“only do the first second”: with that dodgy option removed, it works
fine. I’d still be interested in advice for taking the standard output
progress report in the method and using it to inform the user of
progress, though. And how to tell the user about uploading progress?
(uploading is slower than the conversion)

#{RAILS_ROOT}/public/ffmpeg/ffmpeg
-i
#{RAILS_ROOT}/public/data/unconverted_movies/temp#{self.id}.#{self.filetype}
-ar 22050 #{RAILS_ROOT}/public/data/movies/mov#{self.id}.flv
-f mjpeg
#{RAILS_ROOT}/public/data/movies/mov_thumbs/mov_thumb#{self.id}.jpeg

##################################################################
#method: execute_ffmpeg
#This method provides some exception tracking and also progress
#tracking for file conversion with ffmpeg.
#TODO: Work out how to use the progress text it puts into
#standard output to show progress to the user.

#NOTE - this method is taken from the blog of Dmytro Shteflyuk:
#Encoding media files in Ruby using ffmpeg/mencoder with progress tracking | Dmytro Shteflyuk's Home
#using-ffmpeg-mencoder-with-progress-tracking/
#params:

##################################################################
def execute_ffmpeg(command)
progress = nil
IO.popen(command) do |pipe|
pipe.each(“\r”) do |line|
if line =~ /Duration: (\d{2}):(\d{2}):(\d{2}).(\d{1})/
duration = (($1.to_i * 60 + $2.to_i) * 60 + $3.to_i) * 10 +
$4.to_i
end
if line =~ /time=(\d+).(\d+)/
if not duration.nil? and duration != 0
p = ($1.to_i * 10 + $2.to_i) * 100 / duration
else
p = 0
end
p = 100 if p > 100
if progress != p
progress = p
print “PROGRESS: #{progress}\n”
$defout.flush
end #if progress
end #if line =~
end#pipe.each
end#IO.popen
raise MediaFormatException if $?.exitstatus != 0
end#method

Peter De Berdt wrote:

On 19 Sep 2007, at 10:24, Max W. wrote:

Upload progress: use one of the many “ajax upload solutions” out
there. I really like SWFUpload, because it’s the Flash file that
streams the upload to the server that keeps track of the upload
progress. Other solutions mostly rely on serverside tracking.

For the progress report on the conversion, your method makes it
impossible, because Rails can only return information at the end of
the request and your method only completes after the conversion. The
only way to accomplish what you’re looking for, is passing the rails
request on to backgroundrb, and use a PeriodicalUpdater (or some push
technology, but that’s even more complex) to query the backgroundrb
worker.

Best regards

Peter De Berdt

Thanks for the uploading tip! As far as conversion goes though, the
method i’m using is writing progress info to standard output, there must
be a simple way of displaying this in a dynamic view? Would i need ajax
again? (i’ve not used ajax at all)

cheers
max

Peter De Berdt wrote:

On 19 Sep 2007, at 16:34, Max W. wrote:

There’s a good introductory blog post at http://www.infoq.com/
articles/BackgrounDRb

Best regards

Peter De Berdt

Cool, thanks for all your help.

max

On 19 Sep 2007, at 16:34, Max W. wrote:

Thanks for the uploading tip! As far as conversion goes though, the
method i’m using is writing progress info to standard output, there
must
be a simple way of displaying this in a dynamic view? Would i need
ajax
again? (i’ve not used ajax at all)

If you just want to capture the output of the command once it’s
finished and not while it’s working on a file (haven’t used ffmpeg
yet so you’ll have to look into the output yourself), you can just
use something like

result = ´ls -l /usr/bin/´

If you want progress (each percentage prints out a new line in the
terminal), you’re best off using backgroundrb to handle the process.

A rails request has the following lifecycle:

  • User enters a url
  • Url is routed to the controller method
  • Controller method executes step by step, so if you use a ´command´
    it’s one of those steps that needs to execute before going to the
    next line of code
  • View is rendered

There’s a good introductory blog post at http://www.infoq.com/
articles/BackgrounDRb

Best regards

Peter De Berdt