swift - 每次使用不同的参数重复过程两次

标签 swift ffmpeg ffprobe

我对编码和 Swift 还很陌生。请原谅我无疑笨拙的代码。

我正在尝试使用主资源包中的 ffprobe 运行进程。实际上,我需要运行它两次,每次使用不同的参数,一次是为了获取我输入的音频文件的持续时间,一次是为了获取完整的输出,以便我可以解析它以获取我可以的数据不能像我可以在单个参数中隔离文件持续时间的方式一样。 (我必须执行两次,因为完整输出实际上并未按照我需要的方式列出以秒为单位的持续时间。)

为了避免大量重复代码,我想在一个函数中执行此操作。这就是我所拥有的:

func ffprobeOperations() {
    var probeArguments = [String]()

    // get full ffprobe output to parse
    let probeArguments1 = [
        "-hide_banner",
        "\(inputFilePath)"]

    // get just file duration in seconds
    let probeArguments2 = [
        "-hide_banner",
        "-v",
        "0",
        "-show_entries",
        "format=duration",
        "-of",
        "compact=p=0:nk=1",
        "\(inputFilePath)"]

    var probePass: Int = 0
    if probePass == 1 {
        probeArguments = probeArguments2
    } else if probePass == 0 {
        probeArguments = probeArguments1
    }

    guard let launchPath = Bundle.main.path(forResource: "ffprobe", ofType: "") else { return }
    do {
        let probeTask: Process = Process()
        probeTask.launchPath = launchPath
        probeTask.arguments = probeArguments
        probeTask.standardInput = FileHandle.nullDevice
        let pipe = Pipe()
        probeTask.standardError = pipe
        probeTask.standardOutput = pipe
        let outHandle = pipe.fileHandleForReading
        outHandle.waitForDataInBackgroundAndNotify()

        var obs1 : NSObjectProtocol!
        obs1 = NotificationCenter.default.addObserver(forName: NSNotification.Name.NSFileHandleDataAvailable,
                                                                                                    object: outHandle, queue: nil) {  notification -> Void in
                                                                                                        let data = outHandle.availableData
                                                                                                        if data.count > 0 {
                                                                                                            if let str = NSString(data: data, encoding: String.Encoding.utf8.rawValue) {
                                                                                                                self.ffmpegLogOutput.string += ("\(str)")
                                                                                                                let range = NSRange(location:self.ffmpegLogOutput.string.count,length:0)
                                                                                                                self.ffmpegLogOutput.scrollRangeToVisible(range)
                                                                                                            }
                                                                                                            outHandle.waitForDataInBackgroundAndNotify()
                                                                                                        } else {
                                                                                                            print("EOF on stderr from process")
                                                                                                            NotificationCenter.default.removeObserver(obs1!)
                                                                                                        }
        }
        var obs2 : NSObjectProtocol!
        obs2 = NotificationCenter.default.addObserver(forName: Process.didTerminateNotification,
                                                                                                    object: probeTask, queue: nil) { notification -> Void in
                                                                                                        print("terminated")
                                                                                                        NotificationCenter.default.removeObserver(obs2!)
        }
        probeTask.launch()
        probeTask.waitUntilExit()
        probePass += 1
    }
}

但是无论我将 probePass += 1 放在函数中的哪个位置,XCode 仍然会警告我条件 probePass == 1 永远不会成立,因此带有第二组参数的传递将永远不会被执行。

我应该在哪里放置 probePass += 1,或者有更好的方法来完成此操作吗?

最佳答案

变量probePass的范围只是函数ffProbeOptions,因为它是在那里创建的。这意味着一旦 ffProbeOptions 完成运行,该变量将被取消初始化。尝试在函数外部定义probePass,这样它就有更大的作用域。这样,每次函数完成时变量都不会被销毁,并且它将跟踪其值(例如 0 或 1)。

像这样:

var probePass = 0
func ffprobeOperations() {
    var probeArguments = [String]()

    // get full ffprobe output to parse
    let probeArguments1 = [
        "-hide_banner",
        "\(inputFilePath)"]

    // get just file duration in seconds
    let probeArguments2 = [
        "-hide_banner",
        "-v",
        "0",
        "-show_entries",
        "format=duration",
        "-of",
        "compact=p=0:nk=1",
        "\(inputFilePath)"]

    if probePass == 1 {
        probeArguments = probeArguments2
    } else if probePass == 0 {
        probeArguments = probeArguments1
    }

    guard let launchPath = Bundle.main.path(forResource: "ffprobe", ofType: "") else { return }
    do {
        let probeTask: Process = Process()
        probeTask.launchPath = launchPath
        probeTask.arguments = probeArguments
        probeTask.standardInput = FileHandle.nullDevice
        let pipe = Pipe()
        probeTask.standardError = pipe
        probeTask.standardOutput = pipe
        let outHandle = pipe.fileHandleForReading
        outHandle.waitForDataInBackgroundAndNotify()

        var obs1 : NSObjectProtocol!
        obs1 = NotificationCenter.default.addObserver(forName: NSNotification.Name.NSFileHandleDataAvailable,
                                                                                                    object: outHandle, queue: nil) {  notification -> Void in
                                                                                                        let data = outHandle.availableData
                                                                                                        if data.count > 0 {
                                                                                                            if let str = NSString(data: data, encoding: String.Encoding.utf8.rawValue) {
                                                                                                                self.ffmpegLogOutput.string += ("\(str)")
                                                                                                                let range = NSRange(location:self.ffmpegLogOutput.string.count,length:0)
                                                                                                                self.ffmpegLogOutput.scrollRangeToVisible(range)
                                                                                                            }
                                                                                                            outHandle.waitForDataInBackgroundAndNotify()
                                                                                                        } else {
                                                                                                            print("EOF on stderr from process")
                                                                                                            NotificationCenter.default.removeObserver(obs1!)
                                                                                                        }
        }
        var obs2 : NSObjectProtocol!
        obs2 = NotificationCenter.default.addObserver(forName: Process.didTerminateNotification,
                                                                                                    object: probeTask, queue: nil) { notification -> Void in
                                                                                                        print("terminated")
                                                                                                        NotificationCenter.default.removeObserver(obs2!)
        }
        probeTask.launch()
        probeTask.waitUntilExit()
        probePass += 1
    }
}

也许实现目标的更优雅的方法是定义一个probeArguments 列表:

let probeArgumentList: [[String]] = [
    [   
        "-hide_banner",
        "\(inputFilePath)"
    ],
    [
        "-hide_banner",
        "-v",
        "0",
        "-show_entries",
        "format=duration",
        "-of",
        "compact=p=0:nk=1",
        "\(inputFilePath)"
    ]
]

然后循环列表

for probeArguments in probeArgumentList {
    ## Perform operation
}

关于swift - 每次使用不同的参数重复过程两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58599902/

相关文章:

ffmpeg - 当文件通过标准输入给出时,ffprobe/ffmpeg 报告不同的视频持续时间

c++ - 复制 avcodec 参数

python - 如何获取 ffprobe 元数据作为变量在 python 中解析

actionscript-3 - ffprobe/ffmpeg : know if a input is a video, 图像或音频

swift - UIBezierPath二次曲线是一条直线

android - 在 Android 中使用 FFMpeg 稳定视频

c++ - 使用 ffmpeg 的非常简单的 qt 应用程序中的段错误

arrays - Swift:检测字符串的首字母何时不等于特定字符?

swift - 通过 UITabBar 启动相机的最佳方式

swift - 在 Vapor 中的哪里创建自己的文件?