I am creating a c++ library for use on iOS (yes, unfortunately it has to be C++) which uses AVCaptureSession to capture video frames, which are delivered via the captureOutput callback. The C++ library is my deliverable product. I have a cocoa touch application to test/demo it. So, it looks like this:
(test app) <-----> (c++ lib(AVFoundation callbacks))
The test app has UI controls and is responsible for almost all graphics. The c++ library renders frames to a UIView via OpenGL.
Are you with me? Good
Okay, first, the user presses a UIButton which makes a call into my library. This call takes 10 seconds or more to complete. So if I put the call directly behind the button click, the UI will be blocked until the library function returns:
-(IBAction)hBut:(id)sender{
[myLib foo]; // takes 10+ seconds to return
}
This is no good. The next thing I tried was to spawn a thread to call the lib:
-(void)callIntoLib{
[myLib foo];
}
-(IBAction)hBut:(id)sender{
[NSThread detach..:myLib selector:foo object:nil];
}
This no longer blocks the UI, but now the video frames callback function never fires (AVCaptureSession's captureOutput). It seems as though the main NSRunLoop has been blocked.
Next I tried the same thing, but with Grand Central Dispatch:
-(IBAction)hBut:(id)sender{
_myQueue = dispatch_queue_create("com.domain.me", NULL); // member variable
dispatch_async(_myQueue,
^{
[myLib foo];
});
}
This has the same behavior. That is, the callback for video frames doesn't fire. Lame
Why is the main NSRunLoop being blocked in the 2nd and 3rd cases? Is there a way to associate the queues with 开发者_如何学编程it?
Does this make sense?
Main thread runs its runLoop by itself, so events from camera were delivered to your library in the first case. Custom threads do not run runLoop, you should do that by yourself.
-(void)callIntoLib {
[myLib foo];
self.callIntoLibExecuted = YES;
}
-(void)threadBody {
@autoreleasepool {
self.callIntoLibExecuted = NO;
[self performSelector:@selector(callIntoLib)
onThread:[NSThread currentThread]
withObject:nil
waitUntilDone:NO];
while (!self.callIntoLibExecuted)
{
@autoreleasepool {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
}
}
}
-(IBAction)hBut:(id)sender {
[NSThread detachNewThreadSelector:@selector(threadBody)
toTarget:self withObject:nil];
}
- Technical Q&A QA1702 How to capture video frames from the camera as images using AV Foundation
This sample code uses only AVCaptureVideoDataOutput -setSampleBufferDelegate:queue: on GCD Serial Queue. It seems that AVCaptureSession must be used with RunLoop. You need to execute your own RunLoop on your thread, or try to modify your C++ lib as this sample code.
精彩评论