Getting return data from a process in XCode

Hi all. I've only been learning Swift a few weeks. I did all the fundamentals tutorials I could find, and now I'm at the point of sort of monkey-see/monkey-do following the examples of others until I figure out how to accomplish what I'm trying to do. Please bear with my ignorance.

I'm building a very simple audio file conversion front-end for ffmpeg for MacOS. Followingthis example, I was able to get ffmpeg working in my app mostly through trial, error, and sheer dumb luck.

Now I need to do something similar with ffprobe, but I don't need it to actually convert a file and create a new one. I just need it to return data on the input file's duration, so that I can do a little math and trim off the last few seconds of the file when it's of indeterminate length, and insert that trim command into my ffmpeg arguments, like so:

func insertTrimArguments() {
	conversionSelection()
	if trimInOutClipsCheckbox.state == .on {
		ffmpegArguments.insert(contentsOf: ["-ss", "00:00:02.000", /*"-t", "duration minus 4.2secs"*/], at: 3)
	}
	else {
	}
}

Imitating the function to launch ffmpeg, I've got this, which uses the command for ffprobe to return a file's duration as the arguments:

// get file duration and subtract 4.2 seconds if "trim in/out clips is enabled, then insert additional arguments into conversionSelection arrays
func getFileDuration() {
	guard let probePath = Bundle.main.path(forResource: "ffprobe", ofType: "") else { return }
	do {
		let probeTask: Process = Process()
		probeTask.launchPath = probePath
		probeTask.arguments = [
			"-v", "error",
			"-show_entries",
			"format=duration", "-of",
			"compact=p=0:nk=1",
			"\(inputFilePath)"]
		probeTask.standardInput = FileHandle.nullDevice
		probeTask.launch()
		probeTask.waitUntilExit()
	}
}

But because I'm just imitating what I've seen and don't really understand how processes WORK, I'm sort of stuck at this point and don't know where to take it from here to get the information I need.

Where do I go from this point to accomplish this?

Are you fishing for standardOutput and/or terminationStatus?

The documentation for Process is here.

And here is another example of using Process that could be useful to you. It includes some aspects your other example didn’t need.

I'm...not sure? I as I understand it from my research trying to figure out how to convert the console output from ffmpeg to a textview, ffmpeg prints its output to StandardError. I imagine ffprobe is much the same?

I just need the duration of the file, either in seconds or in hexigesimal. (hh:mm:ss.000)

I will read up on the links you shared and hopefully that will give me a better idea of what exactly I'm trying to get back.

I'm starting to wonder if it would be better to use AVFoundation for this, but I wasn't sure if that was only for iOS apps or if it could be used in MacOS apps as well. It would certainly be the simpler option. I think I got so caught up in thinking I needed to run everything I was doing through ffmpeg that I forgot there are other ways to do it.

AVFoundation is Apple‐wide. Whether it is simpler or not is for someone else to say; I have no experience with it.

I don’t know what those particular tools do, but Process has standardError in addition to standardOutput. The example I linked above ignores the difference and collects both in one place.

I started using ffmpeg with this app because it has some options that AVFoundation doesn't for converting audio files. But I suppose that doesn't mean I have to use it and its associated tools for every aspect of what I'm doing? idk. Information on how to incorporate all its functionality into a Swift/Xcode project is a little thin on the ground and way above my level of understanding, so I may be making this harder on myself than it has to be.

Basically, according tothis post, the way to get audio duration is to use ffprobe to get the duration, and then if you want to trim the end off an audiofile of indeterminate length, you subtract the fixed amount to be trimmed from the duration you retrieved with ffprobe, and use the resulting file length as one of your ffmpeg arguments.

Which I could do from a command line, no problem. But I need to do it using my app, which means I need to tell Swift how to do it and that is, alas, way above my head at this point.

Presumably all you are missing is attaching pipes to listen for output and then some processing to turn that data stream back into a string. If you make a single Swift function out of that (or just import the package that contains the example I linked above), then you can just call the function almost the same as using the command line. At that point you should be picking up any error messages the process prints, so it should be easy to debug what exactly you have to send as arguments.

Thank you. I admit that at my present level of learning, I'm a little intimidated by the complexity of that example you linked, but I will work on trying to understand what the code is doing so I can use it. Thank you so much for taking the time to help me.

Terms of Service

Privacy Policy

Cookie Policy