代码之家  ›  专栏  ›  技术社区  ›  user1904273

使用avfoundation显示avvideocapture会话的异步静止图像输出

  •  0
  • user1904273  · 技术社区  · 6 年前

    我正在预览模式下拍摄视频,希望显示相机拍摄的静止图像。

    我目前将图像和捕获输出保存到接口中定义的ivars,如下所示:

    UIImage *snapshot
    AVCaptureStillImageOutput* stillImageOutput;
    

    视频显示正常。但是,当我尝试捕获和显示静止图像时,没有显示任何内容,事实上,调试器会显示stillimageoutput和image为零。我认为这可能是异步捕获的一个时间问题,我需要使用一个完成处理程序,但是我在完成处理程序上很弱。

    捕获静止图像后立即显示而不占用用户界面的正确方法是什么:

    要捕获静止的代码:

    - (void)takeSnapshot {
     AVCaptureConnection *videoConnection = nil;
     for (AVCaptureConnection *connection in stillImageOutput.connections) {
     for (AVCaptureInputPort *port in [connection inputPorts]) {
     if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
     videoConnection = connection;
     break;
     }
     }
     if (videoConnection) {
     break;
     }
     }
     [stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection
     completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
     if (imageDataSampleBuffer != NULL) {
     NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
     snapshot = [UIImage imageWithData:imageData];
     }
     }];
     }
    

    显示静止的代码。请注意,缺少可能是问题的完成处理程序,但是,我不确定如何编写它…

     [self takeSnapshot];
     self.imageView.image = snapshot;
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   R4N    6 年前

    captureStillImageAsynchronouslyFromConnection:completionHandler

    // this correlates to your takeSnapshot method
    // you want to add a completion portion to this method
    - (void)doSomethingAsynchronouslyWithCompletion:(void (^)(NSData *completionData))completion {
        // call your other async method
        [self anotherAsyncMethodWithItsOwnCompletion:^(NSData *completionDataFromSecondMethod) {
            if (completionDataFromSecondMethod.length > 0) {
                // this is where you would receive the CMSampleBufferRef from the completion handler of captureStillImageAsynchronouslyFromConnection:completionHandler
                // and convert it over to to data
                // make sure the completion block isn't nil if it's nullable
                if (completion) {
                    // you would want to pass back the NSData imageData in the completion block here
                    completion(completionDataFromSecondMethod);
                }
            }
        }];
    }
    
    // this method would simulate the captureStillImageAsynchronouslyFromConnection:completionHandler: method
    - (void)anotherAsyncMethodWithItsOwnCompletion:(void (^)(NSData * completionDataFromSecondMethod))anotherCompletion {
        // this is just to simulate some time waiting for the asnyc task to complete
        // never call sleep in your own code
        sleep(3);
        if (anotherCompletion) {
            // this simulates the fake CFSampleBufferRef passed back by the captureStillImage...
            NSData *fakeCompletionData = [@"FakeCompletionString" dataUsingEncoding:NSUTF8StringEncoding];
            anotherCompletion(fakeCompletionData);
        }
    }
    

        [self doSomethingAsynchronouslyWithCompletion:^(NSData *completionData) {
            if (completionData.length > 0) {
                // come back on the main queue to modify any UI Elements
                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                    // this is where you want want to set your self.imageView.image
                    // self.imageView.image = [UIImage imageWithData:{{dataFromCompletion}}]
                    NSLog(@"The completionString result = %@", [[NSString alloc] initWithData:completionData encoding:NSUTF8StringEncoding]);
                }];
            }
        }];
    

    http://goshdarnblocksyntax.com