16

ビデオの静止フレームをオンザフライで処理する iOS アプリケーション (私の最初のアプリケーション) を構築しています。これを掘り下げるために、Appleの AV* ドキュメントの例に従いました。

このプロセスには、入力 (カメラ) と出力の設定が含まれます。出力はデリゲート (この場合はコントローラー自体) で機能します (必要なメソッドに準拠し、実装します)。

私が抱えている問題は、デリゲート メソッドが呼び出されないことです。以下のコードはコントローラーの実装で、いくつかの NSLog があります。「開始」メッセージは表示されますが、「呼び出されたデリゲート メソッド」は表示されません。

このコードはすべて、「AVCaptureVideoDataOutputSampleBufferDelegate」プロトコルを実装するコントローラー内にあります。

- (void)viewDidLoad {

    [super viewDidLoad];

    // Initialize AV session    
        AVCaptureSession *session = [AVCaptureSession new];

        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
            [session setSessionPreset:AVCaptureSessionPreset640x480];
        else
            [session setSessionPreset:AVCaptureSessionPresetPhoto];

    // Initialize back camera input
        AVCaptureDevice *camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

        NSError *error = nil;

        AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:camera error:&error];

        if( [session canAddInput:input] ){
            [session addInput:input];
        }


    // Initialize image output
        AVCaptureVideoDataOutput *output = [AVCaptureVideoDataOutput new];

        NSDictionary *rgbOutputSettings = [NSDictionary dictionaryWithObject:
                                           [NSNumber numberWithInt:kCMPixelFormat_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
        [output setVideoSettings:rgbOutputSettings];
        [output setAlwaysDiscardsLateVideoFrames:YES]; // discard if the data output queue is blocked (as we process the still image)


        //[output addObserver:self forKeyPath:@"capturingStillImage" options:NSKeyValueObservingOptionNew context:@"AVCaptureStillImageIsCapturingStillImageContext"];

        videoDataOutputQueue = dispatch_queue_create("VideoDataOutputQueue", DISPATCH_QUEUE_SERIAL);
        [output setSampleBufferDelegate:self queue:videoDataOutputQueue];


        if( [session canAddOutput:output] ){
            [session addOutput:output];
        }

        [[output connectionWithMediaType:AVMediaTypeVideo] setEnabled:YES];


    [session startRunning];

    NSLog(@"started");


}


- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {

        NSLog(@"delegate method called");

        CGImageRef cgImage = [self imageFromSampleBuffer:sampleBuffer];

        self.theImage.image = [UIImage imageWithCGImage: cgImage ];

        CGImageRelease( cgImage );

}

注: iOS 5.0 をターゲットとしてビルドしています。

編集:

別の問題の解決策を求めているにもかかわらず、私のコードが本来すべきことを正確に実行しているという質問を見つけました。その質問のコードをそのまま空のxcodeアプリにコピーし、NSLogsをcaptureOutput関数に追加しましたが、呼び出されません。これは構成の問題ですか? 足りないものはありますか?

4

4 に答える 4

33

Yoursessionはローカル変数です。その範囲は に限定されていviewDidLoadます。これは新しいプロジェクトなので、ARC を使用していると言っても過言ではないと思います。その場合、そのオブジェクトはリークしないため、リンクされた質問で行われたように存続し続けます。むしろ、コンパイラはviewDidLoad終了前にオブジェクトの割り当てが解除されるようにします。

したがって、セッションは存在しないため、実行されていません。

(余談: はself.theImage.image = ...メイン キューの UIKit アクションを実行するため、安全ではありませdispatch_asyncdispatch_get_main_queue()

したがって、サンプル修正:

@implementation YourViewController
{
     AVCaptureSession *session;
}

- (void)viewDidLoad {

    [super viewDidLoad];

    // Initialize AV session    
        session = [AVCaptureSession new];

        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
            [session setSessionPreset:AVCaptureSessionPreset640x480];
        else
         /* ... etc ... */
}


- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {

        NSLog(@"delegate method called");

        CGImageRef cgImage = [self imageFromSampleBuffer:sampleBuffer];

        dispatch_sync(dispatch_get_main_queue(),
        ^{
            self.theImage.image = [UIImage imageWithCGImage: cgImage ];
            CGImageRelease( cgImage );
         });
}

最近では、ほとんどの人がインスタンス変数名の先頭にアンダースコアを使用することを推奨していますが、簡単にするために省略しました。診断が正しいことを確認した後、Xcode の組み込みのリファクタリング ツールを使用して修正できます。

をメイン キューに送信されたブロック内に移動しCGImageReleaseて、その有効期間がキャプチャを超えてUIImage. ブロックにキャプチャされたときに CoreFoundation オブジェクトの有効期間が自動的に延長されることを確認するドキュメントをすぐに見つけることができません。

于 2012-11-26T05:36:11.197 に答える
19

didOutputSampleBufferデリゲート メソッドが呼び出されない理由がもう 1 つあります。ファイルへの保存サンプル バッファーの出力接続の取得は相互に排他的です。つまり、セッションに既に がAVCaptureMovieFileOutputあり、その後に を追加すると、デリゲート メソッドAVCaptureVideoDataOutputのみが呼び出されます。AVCaptureFileOutputRecordingDelegate

参考までに、フレームワークのドキュメントでこの制限の明示的な説明を見つけることができませんでしたが、このSO answerAV Foundationに記載されているように、Apple サポートは数年前にこれを確認しました。

この問題を解決する 1 つの方法は、記録されたフレームを完全に削除し、デリゲート メソッドでAVCaptureMovieFileOutputファイルに手動で書き込み、カスタム バッファー データ処理を行うことです。これら2つのSOの回答が役立つdidOutputSampleBuffer場合があります。

于 2014-12-30T11:52:41.133 に答える