IPhoneで静止画を撮るのに新しいAVFoundation framework
を使おうとしています。
ボタンを押すと、この方法が呼び出されます。シャッター音は聞こえますが、ログ出力が見えません。このメソッドを数回呼び出すと、カメラのプレビューがフリーズします。
captureStillImageAsynchronouslyFromConnection
の使い方に関するチュートリアルはありますか?
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:
[[self stillImageOutput].connections objectAtIndex:0]
completionHandler:^(CMSampleBufferRef imageDataSampleBuffer,
NSError *error) {
NSLog(@"inside");
}];
-(void)initCapture { AVCaptureDeviceInput * captionInput = [AVCaptureDeviceInput deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] error:nil]; [。 dispatch_queue_t queue; queue = dispatch_queue_create( "cameraQueue"、NULL); [captureOutput setSampleBufferDelegate:self queue:queue]; dispatch_release (キュー); NSString * key =(NSString *)kCVPixelBufferPixelFormatTypeKey; NSNumber *値= [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 = AVLayerVideoGravityResizeAspect [self.view.layer addSublayer:self.prevLayer]; //デフォルトのファイル出力を設定します AVCaptureStillImageOutput * _stillImageOutput = [[[AVCaptureStillImageOutput alloc] init] autorelease]; NSDictionary * outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVide oCodecJPEG、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]; }
4.0がまだベータ版であったときに、この問題が発生しました。私はかなりのことを試しました。ここに行きます:
結局、ビデオフレームをキャプチャするだけでした。 「写真を撮る」ボタンは単にフラグを設定します。ビデオフレームコールバックでは、フラグが設定されている場合、UIImage *の代わりにビデオフレームを返します。これは私たちの画像処理のニーズには十分でした—「写真を撮る」は主に存在するので、ユーザーは否定的な応答(およびバグレポートを送信するオプション)を得ることができます。 2/3/5メガピクセルの画像は処理に時間がかかるため、実際には必要ありません。
ビデオフレームが十分でない場合(つまり、高解像度の画像キャプチャの間にファインダーフレームをキャプチャしたい場合)、両方のプリセットを設定できる唯一の方法であるため、最初に複数のAVCaptureセッションを使用してそれらが修正されたかどうかを確認します。
おそらくバグを提出する価値があります。 4.0GMのリリースに関するバグを報告しました。 Appleいくつかのサンプルコードを求められましたが、それまでにビデオフレームの回避策を使用することにし、リリースするリリースがありました。
さらに、「低」プリセットはvery低解像度です(結果として低解像度、低フレームレートのビデオプレビューになります)。可能な場合は640x480を選択し、使用できない場合はMediumにフォールバックします。
たくさんの試行錯誤の末、私はこれを行う方法を考え出しました。
ヒント:Appleの公式ドキュメントは-単に-間違っています。彼らがあなたに与えるコードは実際には機能しません。
私はそれをステップバイステップの説明でここに書きました:
リンクにはたくさんのコードがありますが、要約すると:
-(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;
}];
}
これは大きな助けになりました-私はAVCamの例に従おうとしてかなり長い間雑草に閉じ込められました。
これは、何が起こっているのかを説明する私のコメントを含む完全な作業プロジェクトです。これは、複数の出力でキャプチャマネージャを使用する方法を示しています。この例では、2つの出力があります。
1つ目は、上記の例の静止画像出力です。
2つ目は、カメラから出力されるビデオへのフレームごとのアクセスを提供します。必要に応じて、フレームで何か面白いことをするためのコードを追加できます。この例では、デリゲートコールバック内から画面上のフレームカウンターを更新しています。
Appleには、これに関するいくつかのメモとサンプルコードがあります。
テクニカルQ&A QA1702:AV Foundationを使用してカメラからビデオフレームを画像としてキャプチャする方法
Adamの答えを使用する必要がありますが、Swift(最近のほとんどの人がおそらくそうしているように)を使用する場合は、ここにSwift =彼のコードの1.2ポート:
import ImageIO
_private var stillImageOutput: AVCaptureStillImageOutput!
_captureSession.startRunning()
の前にstillImageOutput
をインスタンス化します:このような:
_stillImageOutput = AVCaptureStillImageOutput()
stillImageOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
captureSession.addOutput(stillImageOutput)
_
次に、このコードを使用して画像をキャプチャします。
_private func captureImage() {
var videoConnection: AVCaptureConnection?
for connection in stillImageOutput.connections as! [AVCaptureConnection] {
for port in connection.inputPorts {
if port.mediaType == AVMediaTypeVideo {
videoConnection = connection
break
}
}
if videoConnection != nil {
break
}
}
print("about to request a capture from: \(stillImageOutput)")
stillImageOutput.captureStillImageAsynchronouslyFromConnection(videoConnection) { (imageSampleBuffer: CMSampleBuffer!, error: NSError!) -> Void in
let exifAttachments = CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, nil)
if let attachments = exifAttachments {
// Do something with the attachments
print("attachments: \(attachments)")
} else {
print("no attachments")
}
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageSampleBuffer)
let image = UIImage(data: imageData)
// Do something with the image
}
}
_
これはすべて、すでにAVCaptureSession
セットアップがあり、私と同じように、そこから静止画を取得する必要があることを前提としています。