从 Pipe (stdout) 获取 ffmpeg 信息

Get ffmpeg info from Pipe (stdout)

我想调用 ffmpeg 来获取视频文件的时长。在 OSX 终端中使用命令时一切正常:

ffmpeg -i MyVideo.MOV 2>&1 | grep "Duration"

我明白了:

  Duration: 00:01:23.53, start: 0.000000, bitrate: 39822 kb/s

它非常适合我。但是现在我在我的代码中尝试了这个调用:

func shell(launchPath: String, arguments: [String]) -> String
{
    let task = Process()
    task.launchPath = launchPath
    task.arguments  = arguments

    let pipe = Pipe()
    task.standardOutput = pipe
    
    do {
        try task.run()
        // task.launch() till 10.12, but now catchable!
    } catch let error as NSError {
        print(error.localizedDescription)
        return ""
    }
    
    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String

    return output
}

此代码适用于所有其他外部命令。但在这里我得到错误:

[NULL @ 0x107808800] Unable to find a suitable output format for '2>&1'
2>&1: Invalid argument

我这样定义 ffmpeg 的参数:

let arguments = ["-i", video.path, "2>&1", "|", "grep \"Duration\"" ]

即使我将它们全部放在一个参数中作为一个更大的字符串,它也不起作用。使用“pipe:1”而不是“2>&1”和其余参数也会导致错误。

有什么办法吗?

2>&1 表示 standardError(Output) 中的所有内容都进入 standardOutput。

嗯,你真的不需要那个,是吗?

为什么不直接读取 standardError(Output) 并自己执行 grep?

let pipe = Pipe()
task.standardError = pipe

... //task.run()

let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = String(data: data, encoding: .utf8)

顺便说一下,让我们避免 NSString 并将 re-casting 加倍为 String

让我们自己也做 grep

let durationLine = output.components(separatedBy: .newlines).first(where: { [=11=].contains("Duration") }) 

步骤:让我们获取一组新行,并找到带有“Duration”的第一行。