4

AV Foundationを使用して、ビデオカメラ(iPhone 4s、iOS 6.1.2)からのフレームを処理しています。AV Foundationプログラミングガイドに従って、AVCaptureSession、AVCaptureDeviceInput、AVCaptureVideoDataOutputを設定しています。captureOutput:didOutputSampleBuffer:fromConnection:すべてが期待どおりに機能し、デリゲートでフレームを受信できます。

また、次のようなプレビューレイヤーセットがあります。

AVCaptureVideoPreviewLayer *videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
[videoPreviewLayer setFrame:self.view.bounds];
videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer insertSublayer:videoPreviewLayer atIndex:0];

つまり、フレーム処理に1秒あたり30フレームは必要なく、とにかく高速に処理することはできません。したがって、このコードを使用してフレーム期間を制限しています。

// videoOutput is AVCaptureVideoDataOutput set earlier
AVCaptureConnection *conn = [videoOutput connectionWithMediaType:AVMediaTypeVideo];
[conn setVideoMinFrameDuration:CMTimeMake(1, 10)];
[conn setVideoMaxFrameDuration:CMTimeMake(1, 2)];

これは正常に機能し、 captureOutputデリゲートが受信するフレームを制限します。

ただし、これによりプレビューレイヤーの1秒あたりのフレーム数も制限され、プレビュービデオの応答が非常に悪くなります。

ドキュメントから、フレーム期間は接続に応じて独立して設定され、プレビューレイヤーには実際に異なるAVCaptureConnectionがあることがわかります。のミックス/最大フレーム期間をチェックする[videoPreviewLayer connection]と、実際にデフォルト(1/30および1/24)に設定されており、AVCaptureVideoDataOutputの接続で設定されている期間とは異なることがわかります。

それで、フレームキャプチャ出力でのみフレーム期間を制限し、プレビュービデオで1 / 24-1 / 30フレーム期間を表示することは可能ですか?どのように?

ありがとう。

4

3 に答える 3

4

が2つあることは正しいですがAVCaptureConnection、最小フレーム期間と最大フレーム期間を個別に設定できるという意味ではありません。これは、同じ物理ハードウェアを共有しているためです。

接続#1が1/5秒のフレーム持続時間で(たとえば)5フレーム/秒の速度でローリングシャッターをアクティブにしている場合、接続#2がフレームで30回/秒同時にシャッターをアクティブにする方法はありません。 1/30秒の持続時間。

必要な効果を得るには、2台のカメラが必要です。

あなたが望むものに近づく唯一の方法は、3月22日の答えでKaelinColclasureによって概説されたものの線に沿ったアプローチに従うことです。

ただし、そのアプローチではもう少し洗練されたオプションがあります。たとえば、スレッドをスリープ状態にするのではなく、カウンタを使用してドロップするフレームを決定できます。そのカウンターを実際のフレームレートに応答させることができます(これはcaptureOutput:didOutputSampleBuffer:fromConnection:、画像データとともにデリゲートに送られるメタデータから取得できます。または、フレームのタイミングを手動で計算することで自分で計算できます)。App Storeの多くの「スローシャッター」アプリと同じように、フレームをドロップするのではなく合成することで、より長い露出を非常に合理的に模倣することもできます(ローリングシャッターのアーティファクトの違いなどの詳細は別として)実際にはありませんそれ1/5秒でスキャンされた1つのフレームと1/25秒でスキャンされてから接着された5つのフレームの間に大きな違いがあります)。

はい、少し手間がかかりますが、1台のビデオカメラを2台のようにリアルタイムで動作させようとしていますが、これは決して簡単なことではありません。

于 2013-03-29T10:58:54.953 に答える
2

このように考えてください。キャプチャデバイスにフレーム期間を制限するように依頼すると、露出が向上します。罰金。より高いフレームレートでプレビューしたい。より高いレートでプレビューする場合、キャプチャデバイス(カメラ)にはフレームを露出するのに十分な時間がないため、キャプチャされたフレームでより良い露出が得られます。これは、キャプチャされたフレームとは異なるフレームをプレビューで表示するように要求するようなものです。

可能であれば、ユーザーエクスペリエンスもネガティブになると思います。

于 2013-03-28T13:00:14.403 に答える
1

Cocoa(Mac OS X)アプリケーションでも同じ問題が発生しました。これが私がそれを解決した方法です:

まず、キャプチャされたフレームを別のディスパッチキューで処理するようにしてください。また、処理する準備ができていないフレームはすべて破棄されていることを確認してください。これがデフォルトですが、依存していることを文書化するために、とにかく下にフラグを設定しました。

    videoQueue = dispatch_queue_create("com.ohmware.LabCam.videoQueue", DISPATCH_QUEUE_SERIAL);
    videoOutput = [[AVCaptureVideoDataOutput alloc] init];
    [videoOutput setAlwaysDiscardsLateVideoFrames:YES];
    [videoOutput setSampleBufferDelegate:self
                                   queue:videoQueue];
    [session addOutput:videoOutput];

次に、デリゲートでフレームを処理するときに、スレッドを目的の時間間隔でスリープさせることができます。デリゲートが処理するために起動していないフレームは、静かに破棄されます。健全性チェックと同じように、ドロップされたフレームをカウントするためのオプションのメソッドを実装します。私のアプリケーションは、この手法を使用してフレームのドロップをログに記録しません。

- (void)captureOutput:(AVCaptureOutput *)captureOutput
  didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer
       fromConnection:(AVCaptureConnection *)connection;
{
    OSAtomicAdd64(1, &videoSampleBufferDropCount);
}

- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
       fromConnection:(AVCaptureConnection *)connection;
{
    int64_t savedSampleBufferDropCount = videoSampleBufferDropCount;
    if (savedSampleBufferDropCount && OSAtomicCompareAndSwap64(savedSampleBufferDropCount, 0, &videoSampleBufferDropCount)) {
        NSLog(@"Dropped %lld video sample buffers!!!", savedSampleBufferDropCount);
    }
    // NSLog(@"%s", __func__);
    @autoreleasepool {
        CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
        CIImage * cameraImage = [CIImage imageWithCVImageBuffer:imageBuffer];
        CIImage * faceImage = [self faceImage:cameraImage];
        dispatch_sync(dispatch_get_main_queue(), ^ {
            [_imageView setCIImage:faceImage];
        });
    }
    [NSThread sleepForTimeInterval:0.5]; // Only want ~2 frames/sec.
}

お役に立てれば。

于 2013-03-22T15:55:37.570 に答える