title: iOS: captureOutput:didOutputSampleBuffer:fromConnection is NOT called
body: <p>I want to pull frames from the live-feed of AVCaptureSession and I am using Apple's AVCam as a test case. Here is the link to AVCam:</p>
  
  <p><a href="https://developer.apple.com/library/ios/samplecode/AVCam/Introduction/Intro.html" rel="nofollow">https://developer.apple.com/library/ios/samplecode/AVCam/Introduction/Intro.html</a></p>
  
  <p>I found that that <code>captureOutput:didOutputSampleBuffer:fromConnection</code> is NOT called and I would like to know why or what I am doing wrong.</p>
  
  <p>Here is what I have done:</p>
  
  <p>(1) I make the <code>AVCamViewController</code> a delegate</p>
  
  <pre><code>@interface AVCamViewController () &lt;AVCaptureFileOutputRecordingDelegate, AVCaptureVideoDataOutputSampleBufferDelegate&gt;
  </code></pre>
  
  <p>(2) I created an <code>AVCaptureVideoDataOutput</code> object and add it to the session</p>
  
  <pre><code>AVCaptureVideoDataOutput *videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
  if ([session canAddOutput:videoDataOutput])
       {
           [session addOutput:videoDataOutput];
       }
  </code></pre>
  
  <p>(3) I added the delegate method and test by logging a random string to test</p>
  
  <pre><code>- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
  {
      NSLog(@"I am called");
  
  }
  </code></pre>
  
  <p>The test application works but captureOutput:didOutputSampleBuffer:fromConnection is not called.</p>
  
  <p>(4) I read on SO that the session variable in <code>AVCaptureSession *session = [[AVCaptureSession alloc] init];</code> being local in viewDidLoad is a possible reason why the delegate is not called and I made it an instance variable of the AVCamViewController class, yet it is not called.</p>
  
  <p>Here is the viewDidLoad method I am testing with (taken from AVCam), I added AVCaptureDataOutput towards the end of the method:</p>
  
  <pre><code>- (void)viewDidLoad
  {
      [super viewDidLoad];
  
      // Create the AVCaptureSession
      session = [[AVCaptureSession alloc] init];
      [self setSession:session];
  
      // Setup the preview view
      [[self previewView] setSession:session];
  
      // Check for device authorization
      [self checkDeviceAuthorizationStatus];
  
      // In general it is not safe to mutate an AVCaptureSession or any of its inputs, outputs, or connections from multiple threads at the same time.
      // Why not do all of this on the main queue?
      // -[AVCaptureSession startRunning] is a blocking call which can take a long time. We dispatch session setup to the sessionQueue so that the main queue isn't blocked (which keeps the UI responsive).
  
      dispatch_queue_t sessionQueue = dispatch_queue_create("session queue", DISPATCH_QUEUE_SERIAL);
      [self setSessionQueue:sessionQueue];
  
      dispatch_async(sessionQueue, ^{
          [self setBackgroundRecordingID:UIBackgroundTaskInvalid];
  
          NSError *error = nil;
  
          AVCaptureDevice *videoDevice = [AVCamViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack];
          AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&amp;error];
  
          if (error)
          {
              NSLog(@"%@", error);
          }
  
          if ([session canAddInput:videoDeviceInput])
          {
              [session addInput:videoDeviceInput];
              [self setVideoDeviceInput:videoDeviceInput];
  
              dispatch_async(dispatch_get_main_queue(), ^{
                  // Why are we dispatching this to the main queue?
                  // Because AVCaptureVideoPreviewLayer is the backing layer for AVCamPreviewView and UIView can only be manipulated on main thread.
                  // Note: As an exception to the above rule, it is not necessary to serialize video orientation changes on the AVCaptureVideoPreviewLayer’s connection with other session manipulation.
  
                  [[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] setVideoOrientation:(AVCaptureVideoOrientation)[self interfaceOrientation]];
              });
          }
  
          AVCaptureDevice *audioDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
          AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&amp;error];
  
          if (error)
          {
              NSLog(@"%@", error);
          }
  
          if ([session canAddInput:audioDeviceInput])
          {
              [session addInput:audioDeviceInput];
          }
  
          AVCaptureMovieFileOutput *movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
          if ([session canAddOutput:movieFileOutput])
          {
              [session addOutput:movieFileOutput];
              AVCaptureConnection *connection = [movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
              if ([connection isVideoStabilizationSupported])
                  [connection setEnablesVideoStabilizationWhenAvailable:YES];
              [self setMovieFileOutput:movieFileOutput];
          }
  
          AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
          if ([session canAddOutput:stillImageOutput])
          {
              [stillImageOutput setOutputSettings:@{AVVideoCodecKey : AVVideoCodecJPEG}];
              [session addOutput:stillImageOutput];
              [self setStillImageOutput:stillImageOutput];
          }
  
          AVCaptureVideoDataOutput *videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
          [videoDataOutput setSampleBufferDelegate:self queue:sessionQueue];
  
          if ([session canAddOutput:videoDataOutput])
          {
              NSLog(@"Yes I can add it");
              [session addOutput:videoDataOutput];
          }
  
      });
  }
  
  - (void)viewWillAppear:(BOOL)animated
  {
      dispatch_async([self sessionQueue], ^{
          [self addObserver:self forKeyPath:@"sessionRunningAndDeviceAuthorized" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:SessionRunningAndDeviceAuthorizedContext];
          [self addObserver:self forKeyPath:@"stillImageOutput.capturingStillImage" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:CapturingStillImageContext];
          [self addObserver:self forKeyPath:@"movieFileOutput.recording" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:RecordingContext];
          [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(subjectAreaDidChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:[[self videoDeviceInput] device]];
  
          __weak AVCamViewController *weakSelf = self;
          [self setRuntimeErrorHandlingObserver:[[NSNotificationCenter defaultCenter] addObserverForName:AVCaptureSessionRuntimeErrorNotification object:[self session] queue:nil usingBlock:^(NSNotification *note) {
              AVCamViewController *strongSelf = weakSelf;
              dispatch_async([strongSelf sessionQueue], ^{
                  // Manually restarting the session since it must have been stopped due to an error.
                  [[strongSelf session] startRunning];
                  [[strongSelf recordButton] setTitle:NSLocalizedString(@"Record", @"Recording button record title") forState:UIControlStateNormal];
              });
          }]];
          [[self session] startRunning];
      });
  }
  </code></pre>
  
  <p>Can someone please tell me why and suggestions on how to fix it?</p>