1

I've to admit that I'm quite inexperienced in Swift, but nonetheless I'm trying to build an OS X app to convert a video in a particular format and size with ffmpeg using Swift. My goal is to have the ffmpeg stdout in a separate window to show the progress to the user. Before posting here, I've read all that exist on the internet about the subject :-) and I've not found yet a solution to my problem of not having any output whatsoever in my textView but only in the Xcode console. I've found this post here: Real time NSTask output to NSTextView with Swift that seems very promising but is not working anyway. I've tried to use the command /bin/sh in the example with the provided arguments in my code and it works like a charm. Probably it's me and my inexperience, but I think that is something related to the way ffmpeg output his progress, that won't work. It seems that even removing the -v and -stat options the ffmpeg command still output to the Xcode console but not in my TextField. I hope that someone can shed a light in my swift coding darkness. Thanks in advance

STEFANO

UPDATE - SOLVED

I had an EUREKA moment and I've assigned the pipe to the standarderror and voilà it worked

import Cocoa

var videoLoadURL = ""

class ViewController: NSViewController {
   @IBOutlet weak var filenameLabel: NSTextField!
   @IBOutlet weak var progressText: NSTextField!
   @IBOutlet weak var progressIndicator: NSProgressIndicator!

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    progressIndicator.isHidden = true
    
}

@IBAction func loadVIdeo(_ sender: NSButton) {
    
    let openPanel = NSOpenPanel()
    openPanel.allowsMultipleSelection = false
    openPanel.canChooseFiles = true
    openPanel.runModal()
    
    if let path = openPanel.url?.lastPathComponent {
        
        filenameLabel.stringValue = path
    }
    
    if let path = openPanel.url?.absoluteURL {
        
        videoLoadURL = path.absoluteString

    }

}

@IBAction func convert(_ sender: NSButton) {
    
    progressIndicator.isHidden = false
    let savePanel = NSSavePanel()
    var videoSaveURL: String = ""
    savePanel.nameFieldStringValue = "Converted_\(filenameLabel.stringValue).mp4"
    savePanel.runModal()
    
    if let path = savePanel.url?.absoluteURL {
        
        videoSaveURL = path.absoluteString
    }

    let startLaunch: CFTimeInterval = CACurrentMediaTime()
    
    progressIndicator.startAnimation(self)
    
    let task = Process()
    task.launchPath = "/usr/local/bin/ffmpeg"
    task.arguments = ["-i", "\(videoLoadURL)", "-y", "-g", "1", "-crf", "29","-b", "0", "-pix_fmt", "yuv420p", "-strict", "-2", "\(videoSaveURL)"]
    let pipe = Pipe()
    task.standardError = pipe
    let outHandle = pipe.fileHandleForReading
    outHandle.waitForDataInBackgroundAndNotify()

    var observer1: NSObjectProtocol!
    observer1 = NotificationCenter.default.addObserver(forName: NSNotification.Name.NSFileHandleDataAvailable, object: outHandle, queue: nil, using: { notification -> Void in
        let data = outHandle.availableData
        if data.count > 0 {
            
            if let str = NSString(data: data, encoding: String.Encoding.utf8.rawValue) {
                
                self.progressText.stringValue = str as String
                
            }
            
            outHandle.waitForDataInBackgroundAndNotify()
            
        } else {
            
            print("EOF on stdout from process")
            NotificationCenter.default.removeObserver(observer1)
        }
        
    })

    var observer2: NSObjectProtocol!
    observer2 = NotificationCenter.default.addObserver(forName: Process.didTerminateNotification, object: task, queue: nil, using: { notification -> Void in
        
        print("terminated")
        NotificationCenter.default.removeObserver(observer2)

    })

    do {
        
        try task.run()
        
    }catch {
        
        print("error")
    }
    
    task.waitUntilExit()
    
    let elapsedTime: CFTimeInterval = CACurrentMediaTime() - startLaunch
    NSSound.beep()
    progressIndicator.stopAnimation(self)
    progressIndicator.isHidden = true
    if task.terminationStatus == 0 {
        
        let alertOK = NSAlert()
        alertOK.messageText = "Tutto bene"
        alertOK.addButton(withTitle:"OK")
        alertOK.addButton(withTitle: "Cancel")
        alertOK.informativeText = "Conversione eseguita in \(elapsedTime) secondi"
        alertOK.runModal()
        
    } else {
        
        let alertOK = NSAlert()
        alertOK.messageText = "Errore"
        alertOK.addButton(withTitle:"OK")
        alertOK.informativeText = "La conversione è fallita"
        alertOK.runModal()
        
    }
}

}

TAFKAS
  • 11
  • 6
  • 1
    Indeed, the tip it's that's in the error output (stderr), not the success one (sdtin). `By default the program logs to stderr` in http://ffmpeg.org/ffmpeg.html#Synopsis – Larme Apr 03 '21 at 13:51
  • Does this answer your question? [How do I enable FFMPEG logging and where can I find the FFMPEG log file?](https://stackoverflow.com/questions/2066076/how-do-i-enable-ffmpeg-logging-and-where-can-i-find-the-ffmpeg-log-file) – Larme Apr 03 '21 at 13:51

0 Answers0