2012-11-22 4 views
12

私は、ビデオ静止フレームをその場で処理するiOSアプリケーションを作成しています。これに没頭するために、Appleのexample from the AV* documentationに続きました。AVCaptureDeviceOutputがデリゲートメソッドcaptureOutputを呼び出さない

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

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

このコードはすべて、「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で構築しています。

編集:私は別の問題への解決策を求めたが、私のコードが行うことになっている正確に何やっていること、questionを見つけた

。私はその問題のコードを空のxcodeアプリにコピーし、captureOutput関数にNSLogsを追加し、呼び出されません。これは構成の問題ですか?私は行方不明のものがありますか?

+2

セッションの実行中にエラーが発生した場合(フレームが取得されていない可能性が高いため)、AVCaptureSessionRuntimeErrorNotification通知を送信します。 '[NSNotificationCenter defaultCenter] addObserver:selector:name:object:];を使用してそれを聞いてください。セレクタが呼ばれたら、ユーザ辞書から' AVCaptureSessionErrorKey'を取得してエラーを見てください。 – lnafziger

+1

入力いただきありがとうございます@Inafziger。私はAVCaptureSessionRuntimeErrorNotificationを許可しましたが、トリガーされていないようです: – SuitedSloth

+0

どのようにView Controllerが作成されるのですか? 「開始しましたか」が出力されますか? – Tommy

答えて

28

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

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

(余談:それはメインキューのUIKitのアクションを実行するのでself.theImage.image = ...が危険であり、あなたはおそらくそれ以上dispatch_get_main_queue()dispatch_asyncしたい)

ので、サンプルの修正:

@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オブジェクトの有効期間が自動的に延長されていることを確認するためのドキュメントをブロック内で取得するとすぐには見つかりません。

+0

それは完全にそれをしてくれてありがとう:) - それdidnセッションをインスタンス変数としてテストするために私には起こりません。もちろん、私はSquareCamを見るために戻ってきました。確かにそこにもあります。 私はこの問題から多くのことを学んだので、それはすべて無駄ではありませんでした。再度、感謝します! – SuitedSloth

+2

私はその解決策を試みましたが、それは私のためには機能しませんでした。他の洞察力を私に与えてもらえますか? – tuler

+1

@tuler私は 'didOutputSampleBuffer'デリゲートメソッドが呼び出されないかもしれない別の理由を見つけました。以下の私の答えをチェックしてください。 http://stackoverflow.com/a/27704982/2979418 –

2

私は

[_session startRunning]; 

を呼び出す前に、私はちょうどaddOutput:

startRunning後を呼び出す開始しています

if ([_session canAddOutput:_videoDataOutput]) 
     [_session addOutput:_videoDataOutput]; 

を呼び出すので、私の場合は問題があるが、それが誰かを助けることだと思います。

+0

@nbanic「cuz」という言葉を「because」に変更するには、_just_の更新をやめてください。これまでにいくつかの回答を編集していますが、これは他の重要な改善点と関連しています。 – doppelgreener

+1

@JonathanHobbsメッセージが届きました。私はそれを中止します。 – nbanic

+9

なぜ、addOutputをsession startRunningの後に呼び出すのですか? – jgvb

16

は、私が見つけたdidOutputSampleBufferデリゲートメソッドが呼び出されない理由もう一つの理由 - GETサンプルバッファ出力接続をファイルに保存は、相互に排他的です。つまり、セッションがすでにAVCaptureMovieFileOutputの場合は、AVCaptureVideoDataOutputを追加すると、AVCaptureFileOutputRecordingDelegateデリゲートメソッドだけが呼び出されます。

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

この問題を解決する方法の1つは、カスタムバッファデータ処理と一緒にdidOutputSampleBufferデリゲートメソッドでファイルに記録されたフレームを完全に手動で書き込むことです。 thesetwo SOの回答が役に立ちます。