Reputation: 3123
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
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
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
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