повторяя процесс дважды с разными аргументами каждый раз - PullRequest
0 голосов
/ 29 октября 2019

Я все еще довольно новичок в программировании и 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, или есть лучший способ сделать это вообще?

1 Ответ

0 голосов
/ 29 октября 2019

Область действия переменной 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
}
...