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:
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.
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 )
NSAssert( self.outputFileURL, @"unable to proceed - no output file");
NSMutableArray* args = [NSMutableArray array];
[args addObjectsFromArray:@[@"-loglevel", @"error", @"-i", url.absoluteString]];
[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;
if( self.ffMPEGTask )
[self.ffMPEGTask launch]; // GO!!!
self.status = XVMediaDownloaderRunning;
self.filesize = 0;