Swift 从管道(标准输出)获取ffmpeg信息

Swift 从管道(标准输出)获取ffmpeg信息,swift,macos,ffmpeg,stdout,Swift,Macos,Ffmpeg,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

我想调用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(输出)中的所有内容都进入standardOutput

你真的不需要,是吗

为什么不直接读取standardError(输出)并自己进行grep呢

let pipe = Pipe()
task.standardError = pipe

... //task.run()

let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = String(data: data, encoding: .utf8)
顺便说一句,让我们避免使用
NSString
,并重复使用
String

让我们自己来做
grep

let durationLine = output.components(separatedBy: .newlines).first(where: { $0.contains("Duration") }) 

步骤:让我们获得一个新行数组,并找到第一行“Duration”。

2>&1
这意味着将错误输出重定向到标准输出,不是吗?你真的需要它吗?您知道您可以手动执行此操作,方法是创建一个新的
管道
,并编写
任务。standardError=newPipe
是的,我知道“2>&1”,但如果没有后续内容,它将无法在终端中工作。这是我首先检查所有命令的地方。根据,它在SDT中输出,所以你为什么不自己做grep呢
task.standardOutput=pipe
=>
task.standardError=pipe
让durationLine=output.components(分隔符:。空格和换行符)。过滤器{$0.contains(“Duration”)}
太棒了!就这样。我不得不重定向standardError,因为我需要的信息不是来自stdout,而是来自stderr!非常感谢,你救了我一天!:-)顺便说一句:“让durationLine…”传递的是前导文本“Duration”,而不是时间。但是我自己用了更多的代码解决了这个问题。
.whitespaces和newlines
我的意思是
.newlines
*