Swift Script stuck while executing command (ffmpeg)

Viewed 265

I'm writing a swift script that uses the bash command ffmpeg. I've been following this excellent guide. Everything works except for when I try to run ffmpeg to convert a video. Normally I can just do ffmpeg -i input.mov output.mp4 to convert a video, which works excellent in the terminal. But when I put it in my script I run into trouble.

This is my swift script:

#!/usr/bin/env swift
import Foundation

let ffmpeg = Process()
ffmpeg.executableURL = URL(fileURLWithPath: "/usr/local/bin/ffmpeg")
ffmpeg.arguments = ["-i", "input.mov", "output.mp4"]

let pipe = Pipe()
ffmpeg.standardOutput = pipe

do{
  try ffmpeg.run()
  let data = pipe.fileHandleForReading.readDataToEndOfFile()
  if let output = String(data: data, encoding: String.Encoding.utf8) {
    print(output)
  }
} catch {
  print("Error")
}

However the process just freezes at the following point and i have to ctrl c to exit:

ffmpeg version 4.2.2-with-options Copyright (c) 2000-2019 the FFmpeg developers
  built with Apple clang version 11.0.3 (clang-1103.0.32.29)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/4.2.2_2 --enable-shared --cc=clang --host-cflags=-fno-stack-check --host-ldflags= --enable-gpl --enable-libaom --enable-libmp3lame --enable-libopus --enable-libsnappy --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --disable-libjack --disable-indev=jack --disable-htmlpages --extra-version=with-options --enable-opencl --enable-videotoolbox
  libavutil      56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100

What am I doing wrong in my script?

1 Answers

You need to add the -nostdin option when calling ffmpeg.

let ffmpeg = Process()
ffmpeg.executableURL = URL(fileURLWithPath: "/usr/local/bin/ffmpeg")
ffmpeg.arguments = ["-nostdin", "-i", "input.mov", "output.mp4"]

ffmpeg is waiting for stdin as input. Here are some useful info from the ffmpeg docs.

Enable interaction on standard input. On by default unless standard input is used as an input. To explicitly disable interaction you need to specify -nostdin.

Credits to jazzbox on the Swift Forum.

Related