3

私の目標は、次のようなカスタム カメラ ビュー コントローラーを作成することです。

  1. 背面カメラと、可能な場合は前面カメラの両方を使用して、4 つのインターフェースのすべての向きで写真を撮ることができます。
  2. プレビュー「ビデオ」とフル解像度の写真を適切に回転およびスケーリングします。
  3. プレビュー「ビデオ」とフル解像度の写真の両方に (単純な) 効果を適用できます。

実装 (iOS 4.2 / Xcode 3.2.5):

要件 (3) により、AVFoundation にドロップダウンする必要がありました。

Technical Q&A QA1702から始めて、次の変更を加えました。

  1. sessionPreset を AVCaptureSessionPresetPhoto に変更しました。
  2. セッションを開始する前に、追加の出力として AVCaptureStillImageOutput を追加しました。

私が抱えている問題は、プレビュー画像 (プレビュー「ビデオ」のフレーム) の処理のパフォーマンスにあります。

imageFromSampleBuffer:まず、サンプル バッファの UIImage の結果を から取得しcaptureOutput:didOutputSampleBuffer:fromConnection:ます。次に、CGGraphicsContext を使用して、画面に合わせて拡大縮小および回転します。

この時点で、フレーム レートは、セッションのビデオ出力で指定されている 15 FPS を既に下回っており、エフェクトを追加すると、10 未満または約 10 まで低下します。メモリ不足のため、すぐにアプリがクラッシュします。

iPhone 4 ではフレーム レートを 9 FPS に、iPod Touch (第 4 世代) では 8 FPS にフレーム レートを下げることに成功しました。

ディスパッチ キューを「フラッシュ」するためのコードもいくつか追加しましたが、実際にどれだけ役立つかはわかりません。基本的に、8 ~ 10 フレームごとに、フレームをcaptureOutput:didOutputSampleBuffer:fromConnection:処理するのではなく、すぐに戻るように信号を送るフラグが設定されます。このフラグは、出力ディスパッチ キューでの同期操作が完了するとリセットされます。

現時点では、フレーム レートが低いことは気にしませんが、明らかに、メモリ クラッシュが少ない状態で出荷することはできません。この場合のメモリ不足の状態を防ぐためのアクションを実行する方法(および/またはディスパッチキューを「フラッシュ」するより良い方法)を知っている人はいますか?

4

2 に答える 2

4

メモリの問題を回避するには、単純に で自動解放プールを作成しますcaptureOutput:didOutputSampleBuffer:fromConnection:

imageFromSampleBuffer:自動解放された UIImage オブジェクトを返すため、これは理にかなっています。さらに、画像処理コードによって作成された自動解放されたオブジェクトをすぐに解放します。

// Delegate routine that is called when a sample buffer was written
- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
fromConnection:(AVCaptureConnection *)connection
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    // Create a UIImage from the sample buffer data
    UIImage *image = [self imageFromSampleBuffer:sampleBuffer];

    < Add your code here that uses the image >

    [pool release];
}

私のテストでは、要求された FPS が非常に高く (60 など)、画像処理が非常に遅い (0.5 秒以上) 場合でも、iPhone 4 または iPod Touch (第 4 世代) でメモリ警告なしで実行されることが示されています。

古い解決策:

Brad が指摘したように、Apple は、UI の応答性を妨げないように、画像処理をバックグラウンド スレッドで行うことを推奨しています。この場合、遅延はあまり気になりませんでしたが、ベスト プラクティスはベスト プラクティスであるため、メイン ディスパッチ キュー / メイン スレッドでこれを実行する代わりに、自動解放プールで上記のソリューションを使用してください。

メモリの問題を防ぐには、新しいディスパッチ キューを作成する代わりに、メインのディスパッチ キューを使用します。

captureOutput:didOutputSampleBuffer:fromConnection:これは、UI を更新するときにメイン スレッドに切り替える必要がないことも意味します。

setupCaptureSession、変更元:

// Configure your output.
dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);
[output setSampleBufferDelegate:self queue:queue];
dispatch_release(queue);

に:

// we want our dispatch to be on the main thread
[output setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
于 2011-02-04T21:47:17.537 に答える
2

根本的により良いアプローチは、OpenGL を使用して、画像関連の重労働をできるだけ多く処理することです (最新の試みで試しているように)。ただし、その場合でも、処理するフレームを構築する際に問題が発生する可能性があります。

フレームの処理中にメモリが蓄積されるのは奇妙に思えますが (私の経験では、フレームを十分に高速に処理できない場合は、フレームの取得を停止するだけです)、Grand Central Dispatch キューが待機している場合、混雑する可能性があります。入出力。

おそらく、ディスパッチ セマフォを使用すると、処理キューへの新しいアイテムの追加を抑制できます。詳細については、Mike Ash の記事「GCD Practicum」を強くお勧めします。この記事では、ディスパッチ セマフォを使用して I/O バウンドのサムネイル処理操作を最適化する方法について説明しています。

于 2011-02-04T04:40:37.763 に答える