Re: Using /dev/stdout in a sandboxed app

Bill Pitcher

looking back I went with

//! Connect the Output Pipes
[aTask setStandardOutput:[NSPipe pipe]];
[aTask setStandardError:[aTask standardOutput]];

//! Tell the Pipe to notify to read in the background and post a notification
[[[aTask standardOutput] fileHandleForReading] readInBackgroundAndNotify];

then grab the data as it comes in.


On 9 Jul 2019, at 4:42 pm, Graham Cox <> wrote:

Hi Chris,

actually I think I am doing that.

it’s a while since i put this code together, and exactly what the arguments are is not so clear now. I set the NSTask.standardOutput to an NSPipe, and I have a callback block that deals with that.

However, I’m also passing the -progress argument to ffmpeg as /dev/stdout. Now ffmpeg has a million options, and the documentation is rather terse. All it says for the -progress option is:

<Screen Shot 2019-07-09 at 4.26.06 pm.png>

I pass /dev/stdout as the url argument because what else could it be? My assumption was that NSTask’s standardOutput basically read from there, it was just a convenient place to hook in. The fact it worked led me never to further question that until now. If you don’t pass the -progress parameter, ffmpeg doesn’t send anything.

So the problem isn’t so much the NSTask, but what to pass as a url parameter to the -progress option.

The gist of the code is (with irrelevant stuff cut for clarity and brevity)

NSPipe* progressPipe = [NSPipe pipe];

progressPipe.fileHandleForReading.readabilityHandler = ^(NSFileHandle* handle )
// parse progress reports to update UI with certain info

// create the FFMPEG task:

NSString* execPath = [[[self class] ffMPEGURL] path];
NSArray* codecArgs = [[[self class] ffMPEGCodecForOption:self.format] componentsSeparatedByString:@" "];

if( codecArgs.count > 0 )
if( self.outputFileURL == nil )
[self requestDelegateCreatesFile];

NSAssert( self.outputFileURL, @"unable to proceed - no output file");

NSMutableArray* args = [NSMutableArray array];

[args addObjectsFromArray:@[@"-loglevel", @"error", @"-i", url.absoluteString]];
[args addObjectsFromArray:codecArgs];
[args addObjectsFromArray:@[@"-progress", @"/dev/stdout", self.outputFileURL.path]]; /<——————————————— set up -progress option

XVLOG(@"ffmpeg arguments: %@", args);

NSTask* theTask = [[NSTask alloc] init];

NSAssert( theTask, @"unable to create NSTask for ffmpeg subprocess");

theTask.launchPath = execPath;
theTask.arguments = args;
theTask.standardOutput = progressPipe;
theTask.qualityOfService = NSQualityOfServiceUserInitiated;

theTask.terminationHandler = ^(NSTask* task)
// termination handler

self.ffMPEGTask = theTask;

[theTask release];

if( self.ffMPEGTask )
[self.ffMPEGTask launch]; // GO!!!
self.status = XVMediaDownloaderRunning;
self.filesize = 0;


On 9 Jul 2019, at 4:01 pm, Chris Hanson <> wrote:

Sure, just use NSTask’s own standardInput, standardOutput, and standardError support with NSPipe. No need to tell the task to send its stdout to some intermediate file that your app then opens and reads from. (Whether it’s in /dev or anywhere else.)

-- Chris

Join to automatically receive all group messages.