Konstantin
Konstantin

Reputation: 3123

How to pass Ruby's STDIN to an external program called by Open3.popen3?

I would like to call ffmpeg from a Ruby script, lets call "vpipe", and I want this Ruby script to act as a filter like command: take its input from a pipe. Its only purpose is to select the first audio stream and delete chapters data if exists:

#!/usr/bin/ruby
require "open3"

output_file=ARGV[0]

cmd=%Q{ffmpeg -y -i - -map 0:v -map 0:a -c:v copy -c:a:0 copy -map_chapters -1 #{output_file}}

Open3.popen3(cmd,:stdin_data=>STDIN)

Then I would like to call my program as follows:

curl http://www.example.com/video.wmv | vpipe processed.wmv

Unfortunately doesn't work, because there is no such an option for popen3 as :stdin_data. I also tried Open3.capture3 which can take this argument, but then I got en error message from curl: "Failed writing body".

Upvotes: 0

Views: 1510

Answers (3)

hagello
hagello

Reputation: 3245

If the last thing that "vpipe" does is calling another command and you want to pass stdin, stdout and stderr without modifications, then using Open3.popen3 is a waste. Use exec instead! It is dead easy.

Upvotes: 0

Arie Xiao
Arie Xiao

Reputation: 14082

When your program is in the downstream of a piped command, its STDIN will be fed with the output of the previous command.

When you use Open3.popen3, you get the full control of the forked process' STDIN, STDOUT, STDERR. You need to manually feed it with the data you want, and consume the output as you wish.

Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
  # consume outputs in STDOUT and STDERR, otherwise the ffmpeg process may be blocked if it produces a lot of outputs
  Thread.new do
    while stdout.read
    end
  end
  Thread.new do
    while stderr.read
    end
  end
  while data = STDIN.read(64)  # read output of the upstream command
    stdin.write(data)          # manually pipe it to the ffmpeg command
  end
  wait_thr.join
end

Upvotes: 3

tadman
tadman

Reputation: 211540

You're missing out on a key feature of popen3, that is it will yield the handles to you and you can do whatever you want with them:

Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
  # Use stdin, stdout, stderr as you wish.
end

Upvotes: 0

Related Questions