2012-11-22 3 views
12

나는 비디오 스틸 프레임을 즉시 처리하는 iOS 응용 프로그램을 개발하고 있습니다. 이것에 들어가기 위해서, 나는 Apple의 example from the AV* documentation을 따랐다.AVCaptureDeviceOutput 대리자 메서드를 호출하지 않습니다. captureOutput

이 프로세스에는 입력 (카메라)과 출력을 설정하는 과정이 포함됩니다. 출력은 위임자 (이 경우 제어기 자체)에서 작동합니다 (필요한 메소드를 준수하고 구현 함).

내가 겪고있는 문제는 위임 메서드가 호출되지 않는다는 것입니다. 아래의 코드는 컨트롤러의 구현이며 두 개의 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); 

} 

참고 : 내가 대상으로 아이폰 OS 5.0 짓고 있어요.

편집 : 나는 다른 문제에 대한 해결책을 요구하지만, 내 코드가 어떻게해야 정확히 무엇을하고있는 것을하는 question을 발견했습니다

. 그 질문에 대한 코드를 빈 xcode 앱에 복사하고 NSLog를 captureOutput 함수에 추가했는데 호출되지 않습니다. 이것은 구성 문제입니까? 내가 빠진 것이 있습니까?

+2

세션을 시작하는 중에 오류가 발생하면 (프레임을 가져 오지 않았기 때문에) 'AVCaptureSessionRuntimeErrorNotification' 알림을 게시합니다. '[NSNotificationCenter defaultCenter] addObserver : selector : name : object :];를 사용하여 이것을 듣고 선택기가 호출되면 사용자 사전에서 'AVCaptureSessionErrorKey'를 가져 와서 오류를 확인하십시오. – lnafziger

+1

@Inafziger 입력 해 주셔서 감사합니다. 내가 AVCaptureSessionRuntimeErrorNotification에 suscribed하지만 트리거하지 않는 것 같습니다 : | – SuitedSloth

+0

무슨 뜻으로 뷰 컨트롤러가 생성됩니까? '시작'에 출력이 표시됩니까? – Tommy

답변

28

session은 로컬 변수입니다. 범위는 viewDidLoad으로 제한됩니다. 이것은 새로운 프로젝트이므로 ARC를 사용하고 있다고 말하는 것이 안전하다고 가정합니다. 이 경우 해당 객체는 누출되지 않으므로 링크 된 질문에서와 같이 계속 살아납니다. 컴파일러는 viewDidLoad 종료 전에 객체의 할당이 해제되도록합니다.

따라서 세션이 더 이상 존재하지 않기 때문에 세션이 실행되고 있지 않습니다.

:;

그래서 (제외하고는 주 큐의 UIKit의 작업을 수행하기 때문에 self.theImage.image = ... 안전하지 않은 당신은 아마 dispatch_async 이상에 dispatch_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 객체가 블록에서 캡처 될 때 수명이 자동으로 연장된다는 것을 확인하기위한 문서를 즉시 찾을 수 없습니다.내가

[_session startRunning]; 

를 호출하기 전에 내가

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

전화를 그냥 addOutput:

startRunning 후 누군가 도움의 희망 전화를 시작하고 있습니다 때문에 내 경우

+0

대단히 감사합니다. :) 세션을 인스턴스 변수로 테스트하는 것은 나에게 일어나지 않는다. 물론, 지금 나는 SquareCam을보기 위해 되돌아 가게된다. 그리고 그것은 확실히 거기에서도있다. 나는이 문제에서 많은 다른 것들을 배웠다. 그래서 그것은 모두 낭비가 아니었다. 다시 한 번 감사드립니다! – SuitedSloth

+2

나는 그 해결책을 시도하고 그것은 나를 위해 작동하지 않았다. 다른 통찰력을 주시겠습니까? – tuler

+1

@tuler 왜'didOutputSampleBuffer' 델리게이트 메소드가 호출되지 않을지 또 다른 이유를 찾았습니다. 내 대답을 아래에서 확인하십시오. http://stackoverflow.com/a/27704982/2979418 –

2

는 문제가있다.

+0

@nbanic 게시물 수정을하지 않고 'cuz'을 'because'로 변경하려면 _just_을 (를) 중지하십시오. 지금까지 몇 가지 해답을 편집 했으므로 다른 중요한 개선이있을 수 있습니다. – doppelgreener

+1

@JonathanHobbs 메시지가 수신되었습니다. – nbanic

+9

왜 addOutput을 세션 startRunning 후에 호출할까요? – jgvb

16

내가 발견 한 didOutputSampleBuffer 대리자 메서드가 호출되지 않는 이유를 또 하나의 이유 - GET 샘플 버퍼 출력 연결을 파일로 저장은 상호 배타적입니다. 즉, 세션에 이미 AVCaptureMovieFileOutput이 있고 AVCaptureVideoDataOutput을 추가하면 AVCaptureFileOutputRecordingDelegate 대리자 메서드 만 호출됩니다.

참조 용으로 AV Foundation 프레임 워크 문서에서이 제한 사항에 대한 명시적인 설명을 찾을 수는 없었지만 Apple 지원팀은이 SO answer에 명시된 바와 같이 몇 년 전에이를 확인했습니다.

이 문제를 해결하는 방법 중 하나는 AVCaptureMovieFileOutput을 완전히 제거하고 사용자 지정 버퍼 데이터 처리와 함께 didOutputSampleBuffer 대리자 메서드의 파일에 기록 된 프레임을 수동으로 작성하는 것입니다. thesetwo 그래서 유용한 답변을 찾을 수 있습니다.

관련 문제