3

i am new to the Mac World. I'm using Swift and i am trying to run external processes one at a time. Now everything works fine, as long, as it is debugged, by which I mean: Run in Xcode with Debugger attached.

I do not change anything and try to run it in the terminal window, from it's place in the "Debug" folder. Now the external process starts but hangs.There is some STDERR output, which I already switched off. And there is DiskIO by the external Task.

let video : NSTask = NSTask()
video.launchPath = "./ffmpeg"
video.arguments = ["-i", "\(item)", "-c:v","copy", "-bsf:v", "h264_mp4toannexb", "-an", "-y", "-loglevel", "quiet", "\(path).h264"]

//also tried without the following two lines
video.standardError = NSFileHandle.fileHandleWithStandardError()
video.standardOutput = NSFileHandle.fileHandleWithStandardOutput()

video.launch()
video.waitUntilExit()

Yes: I copied everything to the current path, so that execution works. It starts but hangs when run from terminal.

Now the Question arises: WHY?! What am I doing wrong here? The easy solution would be to always run it in Xcode, but as you might imagine, that is quite inconvenient with a command line tool.

Andreas
  • 828
  • 4
  • 15

1 Answers1

6

You need to redirect stdin from /dev/null. ffmpeg has an open stdin and is waiting for more data on that pipe.

video.standardInput = NSFileHandle.fileHandleWithNullDevice()

Note that you don't need your assignments to standardError and standardOutput. Those are the default settings.

This works in Xcode because the debugger closes stdin for you.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Thanks for the solution, works perfectly. I wonder do you have any resource to help understand why close the `standardInput` would solve this issue? Thanks! – Honghao Z Jan 10 '19 at 08:39
  • 1
    @HonghaoZhang See http://ffmpeg.org/ffmpeg.html and read the docs on the `-stdin`. As it notes, you could also solve this problem by passing `-nostdin` as a parameter instead of closing stdin. The solution they list of `< /dev/null` is identical to this answer (just the shell way to do it rather than the Swift way). – Rob Napier Jan 10 '19 at 13:26
  • Thanks so much! Using `-nostdin` is much better if the process is run in background. – Honghao Z Jan 11 '19 at 21:59