10

我试图在我的 iPhone 应用程序中嵌入一个简单的视图来快速拍摄快照。一切正常,但我在相机启动时间方面遇到了一些问题。在 Apple 示例项目中,AVCaptureSession-startRunning没有在主线程上执行,这似乎是必要的。我在视图初始化期间设置捕获会话,并在单独的线程中启动它。现在我添加AVCaptureVideoPreviewLayerin -didMoveToSuperview。没有多线程一切都很好(用户界面被阻塞了大约一秒钟),但使用 GCD 用户界面有时可以工作,有时用户界面“解冻”或显示预览需要太长时间。

如何在不阻塞主线程的情况下以可靠的方式处理相机的启动延迟(延迟本身不是问题)?

我希望你们能理解我的问题:D

提前致谢!

顺便说一句:这是我的概念验证项目(没有 GCD)我现在正在为另一个应用程序重用:http: //github.com/dariolass/QuickShotView

4

2 回答 2

10

So I figured it out by myself. This code works for me and produces the least UI freezing:

- (void)willMoveToSuperview:(UIView *)newSuperview {
    //capture session setup
    AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.rearCamera error:nil];
    AVCaptureStillImageOutput *newStillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
                            AVVideoCodecJPEG, AVVideoCodecKey,
                            nil];
    [newStillImageOutput setOutputSettings:outputSettings];

    AVCaptureSession *newCaptureSession = [[AVCaptureSession alloc] init];

    if ([newCaptureSession canAddInput:newVideoInput]) {
        [newCaptureSession addInput:newVideoInput];
    }

    if ([newCaptureSession canAddOutput:newStillImageOutput]) {
        [newCaptureSession addOutput:newStillImageOutput];
        self.stillImageOutput = newStillImageOutput;
        self.captureSession = newCaptureSession;
    }
    // -startRunning will only return when the session started (-> the camera is then ready)
    dispatch_queue_t layerQ = dispatch_queue_create("layerQ", NULL);
    dispatch_async(layerQ, ^{
        [self.captureSession startRunning];
        AVCaptureVideoPreviewLayer *prevLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.captureSession];
            prevLayer.frame = self.previewLayerFrame;
            prevLayer.masksToBounds = YES;
            prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
            prevLayer.cornerRadius = PREVIEW_LAYER_EDGE_RADIUS;
        //to make sure were not modifying the UI on a thread other than the main thread, use dispatch_async w/ dispatch_get_main_queue
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.layer insertSublayer:prevLayer atIndex:0];
        });
    });
}
于 2013-04-05T22:39:06.247 回答
-1

我认为另一种避免的方法是您可以将“启动相机”代码放在 viewDidAppear 中,而不是将它们放在 viewWillAppear 中。

于 2013-11-06T00:50:01.583 回答