21

AVFoundation frameworkiPhoneで静止画を撮るために新しいものを使おうとしています。

ボタンを押すと、このメソッドが呼び出されます。シャッター音は聞こえますが、ログ出力が見えません。このメソッドを数回呼び出すと、カメラのプレビューがフリーズします。

使い方のチュートリアルはありますcaptureStillImageAsynchronouslyFromConnectionか?

[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:
                [[self stillImageOutput].connections objectAtIndex:0]
                     completionHandler:^(CMSampleBufferRef imageDataSampleBuffer,
                            NSError *error) {
                                              NSLog(@"inside");
                            }];
- (無効)initCapture {
    AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput
                                          deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]
                                          エラー: なし];

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

    captureOutput.alwaysDiscardsLateVideoFrames = YES;

    dispatch_queue_t キュー;
    queue = dispatch_queue_create("cameraQueue", NULL);
    [captureOutput setSampleBufferDelegate:self queue:queue];
    ディスパッチ_リリース(キュー);

    NSString* キー = (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 = AVLayerVideoGravityResizeAspectFill;

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


    // デフォルトのファイル出力をセットアップします
    AVCaptureStillImageOutput *_stillImageOutput = [[[AVCaptureStillImageOutput alloc] init] autorelease];
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
                                    AVVideoCodecJPEG、AVVideoCodecKey、
                                    なし];
    [_stillImageOutput setOutputSettings:outputSettings];
    [outputSettings リリース];
    [self setStillImageOutput:_stillImageOutput];   

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

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

}
4

5 に答える 5

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;
     }];
}
于 2011-04-14T18:22:49.320 に答える
16

この問題は、4.0 がまだベータ版だったときに発生しました。私はかなりのことを試しました。ここに行きます:

  • AVCaptureStillImageOutput と AVCaptureVideoDataOutput がうまく連携していないようです。ビデオ出力が実行されている場合、画像出力は完了していないように見えます (電話をスリープ状態にしてセッションを一時停止するまで; その後、単一の画像を取得しているように見えます)。
  • AVCaptureStillImageOutput は、AVCaptureSessionPresetPhoto でのみ適切に機能するようです。そうしないと、効果的に JPEG でエンコードされたビデオ フレームが取得されます。高品質の BGRA フレームを使用することもできます (ちなみに、カメラのネイティブ出力は BGRA のようです。2vuy/420v のカラー サブサンプリングはないようです)。
  • ビデオ (写真以外のすべて) と写真のプリセットは根本的に異なるようです。セッションが写真モードの場合、ビデオ フレームは取得されません (エラーも発生しません)。多分彼らはこれを変えた...
  • 2 つのキャプチャ セッション (1 つはビデオ プリセットとビデオ出力、もう 1 つは写真プリセットと画像出力) を持つことはできないようです。彼らはこれを修正したかもしれません。
  • セッションを停止し、プリセットを写真に変更し、セッションを開始して写真を撮り、写真が完成したら停止し、プリセットを元に戻して、再び開始することができます。これにはしばらく時間がかかり、ビデオ プレビュー レイヤーが停止して見栄えが悪くなります (露出レベルが再調整されます)。これもベータ版でデッドロックすることがありました (-stopRunning を呼び出した後、session.running はまだ YES でした)。
  • AVCaptureConnection を無効にできる場合があります (動作するはずです)。この行き詰まりを覚えています。彼らはこれを修正したかもしれません。

ビデオフレームをキャプチャするだけになりました。「写真を撮る」ボタンは、フラグを設定するだけです。ビデオ フレーム コールバックでは、フラグが設定されている場合、UIImage* の代わりにビデオ フレームを返します。これは、私たちの画像処理のニーズには十分でした。「写真を撮る」という機能が大部分存在するため、ユーザーは否定的な反応 (およびバグ レポートを送信するオプション) を得ることができます。2/3/5 メガピクセルの画像は処理に時間がかかるため、実際には必要ありません。

ビデオ フレームが十分でない場合 (つまり、高解像度の画像キャプチャの間にビューファインダー フレームをキャプチャしたい場合)、複数の AVCapture セッションを使用して修正されたかどうかを最初に確認します。これが、両方のプリセットを設定できる唯一の方法だからです。

おそらくバグを報告する価値があります。私は 4.0 GM のリリースに関してバグを報告しました。Apple からサンプル コードの提供を求められましたが、その時までにビデオ フレームの回避策を使用することに決め、リリースする必要がありました。

さらに、「低」プリセットは非常に低解像度です (その結果、低解像度、低フレームレートのビデオ プレビューになります)。利用できる場合は 640x480 を選び、利用できない場合は Medium にフォールバックします。

于 2010-10-03T01:10:26.260 に答える
6

これは大きな助けになりました-私はAVCamの例に従おうとしてかなり長い間雑草にとらわれていました。

これは、何が起こっているのかを説明する私のコメントを含む完全な作業プロジェクトです。これは、複数の出力でキャプチャマネージャを使用する方法を示しています。この例では、2つの出力があります。

1つ目は、上記の例の静止画像出力です。

2つ目は、カメラから出力されるビデオへのフレームごとのアクセスを提供します。必要に応じて、フレームで何か面白いことをするためのコードを追加できます。この例では、デリゲートコールバック内から画面上のフレームカウンターを更新しています。

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

于 2011-11-13T20:19:02.460 に答える
3

Appleには、これに関するいくつかのメモとサンプルコードがあります。

技術的なQ&A QA1702:AVFoundationを使用してカメラからビデオフレームを画像としてキャプチャする方法

于 2010-10-03T21:00:53.530 に答える
0

Adamの回答を使用する必要がありますが、Swift を使用する場合 (おそらく最近のほとんどの人がそうしているように)、彼のコードの Swift 1.2 ポートを次に示します。

  1. 確認してくださいimport ImageIO
  2. プロパティを追加するprivate var stillImageOutput: AVCaptureStillImageOutput!
  3. stillImageOutputの前にインスタンス化captureSession.startRunning():

このような:

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これはすべて、私が行ったように、すでにセットアップがあり、そこから静止画を取得する必要があることを前提としています.

于 2016-02-11T00:09:30.163 に答える