iPhone SDK 4 AVFoundation - 如何正确使用captureStillImageAsynchronouslyFromConnection?

dan*_*dan 21 iphone camera avfoundation

我正在尝试使用新AVFoundation framework的iPhone拍摄静态照片.

按下按钮可以调用此方法.我可以听到快门声,但我看不到日志输出.如果我多次调用此方法,相机预览将冻结.

有没有任何教程如何使用captureStillImageAsynchronouslyFromConnection

[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:
                [[self stillImageOutput].connections objectAtIndex:0]
                     completionHandler:^(CMSampleBufferRef imageDataSampleBuffer,
                            NSError *error) {
                                              NSLog(@"inside");
                            }];
Run Code Online (Sandbox Code Playgroud)
- (void)initCapture {
    AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput 
                                          deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] 
                                          error:nil];

    AVCaptureVideoDataOutput *captureOutput = [[AVCaptureVideoDataOutput alloc] init];

    captureOutput.alwaysDiscardsLateVideoFrames = YES; 

    dispatch_queue_t queue;
    queue = dispatch_queue_create("cameraQueue", NULL);
    [captureOutput setSampleBufferDelegate:self queue:queue];
    dispatch_release(queue);

    NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey; 
    NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]; 
    NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key]; 
    [captureOutput setVideoSettings:videoSettings]; 

    self.captureSession = [[AVCaptureSession alloc] init];
    self.captureSession.sessionPreset = AVCaptureSessionPresetLow;

    [self.captureSession addInput:captureInput];
    [self.captureSession addOutput:captureOutput];

    self.prevLayer = [AVCaptureVideoPreviewLayer layerWithSession: self.captureSession];

    [self.prevLayer setOrientation:AVCaptureVideoOrientationLandscapeLeft];

    self.prevLayer.frame = CGRectMake(0.0, 0.0, 480.0, 320.0);
    self.prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;

    [self.view.layer addSublayer: self.prevLayer];


    // Setup the default file outputs
    AVCaptureStillImageOutput *_stillImageOutput = [[[AVCaptureStillImageOutput alloc] init] autorelease];
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
                                    AVVideoCodecJPEG, AVVideoCodecKey,
                                    nil];
    [_stillImageOutput setOutputSettings:outputSettings];
    [outputSettings release];
    [self setStillImageOutput:_stillImageOutput];   

    if ([self.captureSession canAddOutput:stillImageOutput]) {
        [self.captureSession addOutput:stillImageOutput];
    }

    [self.captureSession commitConfiguration];
    [self.captureSession startRunning];

}

Ada*_*dam 62

经过大量的反复试验,我找到了如何做到这一点.

提示:Apple的官方文档 - 简单 - 错误.他们给你的代码实际上并不起作用.

我在这里写了一步一步的说明:

http://red-glasses.com/index.php/tutorials/ios4-take-photos-with-live-video-preview-using-avfoundation/

链接上有很多代码,但总结如下:

-(void) viewDidAppear:(BOOL)animated
{
    AVCaptureSession *session = [[AVCaptureSession alloc] init];
    session.sessionPreset = AVCaptureSessionPresetMedium;

    CALayer *viewLayer = self.vImagePreview.layer;
    NSLog(@"viewLayer = %@", viewLayer);

    AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];

    captureVideoPreviewLayer.frame = self.vImagePreview.bounds;
    [self.vImagePreview.layer addSublayer:captureVideoPreviewLayer];

    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    NSError *error = nil;
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
    if (!input) {
        // Handle the error appropriately.
        NSLog(@"ERROR: trying to open camera: %@", error);
    }
    [session addInput:input];

stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVideoCodecJPEG, AVVideoCodecKey, nil];
[stillImageOutput setOutputSettings:outputSettings];

[session addOutput:stillImageOutput];

    [session startRunning];
}

-(IBAction) captureNow
{
    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; }
    }

    NSLog(@"about to request a capture from: %@", stillImageOutput);
    [stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error)
    {
         CFDictionaryRef exifAttachments = CMGetAttachment( imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);
         if (exifAttachments)
         {
            // Do something with the attachments.
            NSLog(@"attachements: %@", exifAttachments);
         }
        else
            NSLog(@"no attachments");

        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
        UIImage *image = [[UIImage alloc] initWithData:imageData];

        self.vImage.image = image;
     }];
}
Run Code Online (Sandbox Code Playgroud)

  • 我不能为此+1.感谢您分享这一点! (4认同)

tc.*_*tc. 16

当4.0仍然处于测试阶段时,我们遇到了这个问题.我尝试了很多东西.开始:

  • AVCaptureStillImageOutput和AVCaptureVideoDataOutput似乎没有很好地相互配合.如果视频输出正在运行,图像输出似乎永远不会完成(直到您通过将手机置于睡眠状态来暂停会话;然后您似乎将单个图像输出).
  • AVCaptureStillImageOutput似乎只能与AVCaptureSessionPresetPhoto合理地工作; 否则你有效地获得JPEG编码的视频帧.不妨使用更高质量的BGRA帧(顺便提一下,相机的原生输出似乎是BGRA;它似乎没有2vuy/420v的颜色子采样).
  • 视频(一切不是照片)和照片预设似乎根本不同; 如果会话处于照片模式,你永远不会得到任何视频帧(你也没有得到错误).也许他们改变了这个......
  • 您似乎没有两个捕获会话(一个具有视频预设和视频输出,一个具有照片预设和图像输出).他们可能已经修好了.
  • 您可以停止会话,将预设更改为照片,开始会话,拍摄照片,以及照片完成后,停止,更改预设,然后重新开始.这需要一段时间,视频预览图层会停滞并且看起来很糟糕(它会重新调整曝光级别).这也偶尔在测试版中陷入僵局(在调用-stopRunning之后,session.running仍为YES).
  • 您可能能够禁用AVCaptureConnection(它应该可以工作).我记得这个僵局; 他们可能已经修好了.

我最终只是捕捉视频帧."拍照"按钮只是设置一个标志; 在视频帧回调中,如果设置了标志,则返回视频帧而不是UIImage*.这足以满足我们的图像处理需求 - "拍照"主要存在,因此用户可以获得否定响应(以及提交错误报告的选项); 我们实际上并不想要2/3/5百万像素图像,因为它们需要很长时间才能处理.

如果视频帧不够好(即你想要在高分辨率图像捕获之间捕获取景器帧),我首先要看看它们是否已使用多个AVCapture会话进行修复,因为这是设置两个预设的唯一方法.

它可能值得归档一个bug.我在4.0 GM的发布时提出了一个错误; Apple问了我一些示例代码,但到那时我决定使用视频帧解决方法并发布了一个版本.

此外,"低"预设是非常低分辨率(并导致低分辨率,低帧率视频预览).如果可用的话,我会去640x480,如果没有,我会回到中等.


Ter*_*ott 6

这是一个巨大的帮助 - 我被困在杂草中一段时间​​试图遵循AVCam的例子.

这是一个完整的工作项目,我的评论解释了正在发生的事情.这说明了如何使用具有多个输出的捕获管理器.在这个例子中有两个输出.

第一个是上面例子的静止图像输出.

第二个提供逐帧访问来自摄像机的视频.如果您愿意,可以添加更多代码以使用框架执行一些有趣的操作.在这个例子中,我只是在委托回调中更新屏幕上的帧计数器.

https://github.com/tdsltm/iphoneStubs/tree/master/VideoCamCaptureExample-RedGlassesBlog/VideoCamCaptureExample-RedGlassesBlog