NSRunLoop 和 GCD 队列

发布于 2024-10-19 23:56:55 字数 1143 浏览 2 评论 0原文

我正在创建一个在 iOS 上使用的 C++ 库(是的,不幸的是它必须是 C++),它使用 AVCaptureSession 来捕获视频帧,这些视频帧通过 captureOutput 回调传递。 C++ 库是我的可交付产品。我有一个可可触摸应用程序来测试/演示它。所以,它看起来像这样:(

测试应用程序)<-----> (c++ lib(AVFoundation callbacks))

测试应用程序具有 UI 控件,负责几乎所有图形。 C++ 库通过 OpenGL 将帧渲染到 UIView。

你和我在一起吗?好的好的


,首先,用户按下一个 UIButton,它会调用我的库。此调用需要 10 秒或更长时间才能完成。因此,如果我将调用直接放在按钮单击后面,则 UI 将被阻塞,直到库函数返回:

-(IBAction)hBut:(id)sender{
    [myLib foo]; // takes 10+ seconds to return
}

这不好。我尝试的下一件事是生成一个线程来调用库:

-(void)callIntoLib{
    [myLib foo];
}

-(IBAction)hBut:(id)sender{
    [NSThread detach..:myLib selector:foo object:nil];
}

这不再阻塞 UI,但现在视频帧回调函数永远不会触发(AVCaptureSession 的 captureOutput)。看起来主要的 NSRunLoop 已经被阻塞了。

接下来我尝试了同样的事情,但是对于 Grand Central Dispatch:

-(IBAction)hBut:(id)sender{
     _myQueue = dispatch_queue_create("com.domain.me", NULL); // member variable
     dispatch_async(_myQueue,
     ^{
          [myLib foo];
     });
}

这具有相同的行为。也就是说,视频帧的回调不会触发。 Lame

为什么主 NSRunLoop 在第二种和第三种情况下被阻塞?有没有办法将队列与其关联起来?

这有道理吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

幽梦紫曦~ 2024-10-26 23:56:55

主线程自行运行其 runLoop,因此在第一种情况下来自相机的事件被传递到您的库。自定义线程不运行 runLoop,您应该自己执行。

-(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];
}

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];
}
扮仙女 2024-10-26 23:56:55

此示例代码仅在 GCD 串行队列上使用 AVCaptureVideoDataOutput -setSampleBufferDelegate:queue:。看来AVCaptureSession必须和RunLoop一起使用。您需要在线程上执行您自己的 RunLoop,或者尝试修改您的 C++ 库作为此示例代码。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文