title: Capture a still image on iOS7 through a console app
body: <p>I am attempting to capture a still image on my Jailbroken iPhone through a console.</p>
  
  <p>Disclaimer: I am a objective-c newbie - most of this code is from: <a href="https://stackoverflow.com/questions/12445403/avcapturestillimageoutput-never-calls-completition-handler">AVCaptureStillImageOutput never calls completition handler</a></p>
  
  <p>I just want to know if it can work in a terminal.</p>
  
  <p>I have tried various examples on SO and none seem to work. My question is - Is it even possible? or does Apple lock this down for some reason (accessing the camera through the terminal might not be allowed etc).</p>
  
  <p>Here is the my current camera.m:</p>
  
  <pre><code>#import &lt;Foundation/Foundation.h&gt;
  #import &lt;CoreVideo/CoreVideo.h&gt;
  #import &lt;CoreMedia/CoreMedia.h&gt;
  #import &lt;AVFoundation/AVFoundation.h&gt;
  #import &lt;ImageIO/CGImageProperties.h&gt;
  #import &lt;stdio.h&gt;
  #import &lt;UIKit/UIKit.h&gt;
  
  @interface Camera : NSObject {
  }
  
  @property (readwrite, retain) AVCaptureStillImageOutput *stillImageOutput;
  - (AVCaptureDevice *)frontFacingCameraIfAvailable;
  - (void)setupCaptureSession;
  - (void)captureNow;
  @end
  
  @implementation Camera
  @synthesize stillImageOutput;
  
  -(AVCaptureDevice *) frontFacingCameraIfAvailable{
  
      NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
      AVCaptureDevice *captureDevice = nil;
  
     for (AVCaptureDevice *device in videoDevices){
  
          if (device.position == AVCaptureDevicePositionFront){
  
              captureDevice = device;
              break;
          }
      }
  
      //  couldn't find one on the front, so just get the default video device.
      if (!captureDevice){
  
          captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
      }
  
      return captureDevice;
  }
  
  -(void) setupCaptureSession {
      AVCaptureSession *session = [[AVCaptureSession alloc] init];
      session.sessionPreset = AVCaptureSessionPresetMedium;
  
      AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer    alloc] initWithSession:session];
      //[self.view.layer addSublayer:captureVideoPreviewLayer];
  
      NSError *error = nil;
      AVCaptureDevice *device = [self frontFacingCameraIfAvailable];
      AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&amp;error];
      if (!input) {
          // Handle the error appropriately.
          NSLog(@"ERROR: trying to open camera: %@", error);
      }
      [session addInput:input];
  
      self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
      NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVideoCodecJPEG, AVVideoCodecKey, nil];
      [self.stillImageOutput setOutputSettings:outputSettings];
  
      [session addOutput:self.stillImageOutput];
  
      [session startRunning];
  }
  
  -(void) captureNow {
      AVCaptureConnection *videoConnection = nil;
      for (AVCaptureConnection *connection in self.stillImageOutput.connections) {
          for (AVCaptureInputPort *port in [connection inputPorts]) {
              if ([[port mediaType] isEqual:AVMediaTypeVideo] ) {
                  videoConnection = connection;
                  break;
              }
          }
          if (videoConnection) { break; }
      }
  
      NSLog(@"about to request a capture from: %@", self.stillImageOutput);
      [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
          NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
          UIImage *image = [[UIImage alloc] initWithData:imageData];
          NSLog(@"image captured: %@", [imageData bytes]);
       }];
  }
  @end
  
  int main(int argc, const char *argv[]) {
      Camera *camera = [[Camera alloc] init];
      [camera setupCaptureSession];
      [camera captureNow];
  }
  </code></pre>
  
  <p>Here is my Makefile:</p>
  
  <pre><code>XCODE_BASE=/Applications/Xcode.app/Contents
  IPHONEOS=$(XCODE_BASE)/Developer/Platforms/iPhoneOS.platform
  SDK=$(IPHONEOS)/Developer/SDKs/iPhoneOS7.1.sdk
  FRAMEWORKS=$(SDK)/System/Library/Frameworks/
  INCLUDES=$(SDK)/usr/include
  
  camera:
      clang   -mios-version-min=7.0 \
              -isysroot $(SDK) \
              -arch armv7 \
              camera.m \
              -lobjc \
              -framework Foundation -framework AVFoundation -framework CoreVideo -framework CoreMedia -framework CoreGraphics -framework CoreImage -framework UIKit -framework ImageIO \
              -o camera
  </code></pre>
  
  <p>Copy camera binary to iPhone:</p>
  
  <pre><code>scp camera root@10.1.1.32:/var/root/camera
  root@10.1.1.32's password:
  camera                                    100%   51KB  51.0KB/s   00:00
  </code></pre>
  
  <p>iPhone result of running the app:</p>
  
  <pre><code>iPhone:~ root# ./camera
  2014-03-21 15:17:55.550 camera[9483:507] about to request a capture from: &lt;AVCaptureStillImageOutput: 0x14e2b940&gt;
  </code></pre>
  
  <p>As you can see, the AVCaptureSession gets setup correctly, the frontal camera is found and set, The AVCaptureConnection gets set correctly.
  However captureStillImageAsynchronouslyFromConnection:completionHandler: never gets called.</p>
  
  <p>Is this even possible to do? Am I doing something wrong?</p>
  
  <p><strong>EDIT:
  I have modified captureNow to sleep on the thread until completionHandler completes and the app just waits forever after starting.</strong></p>
  
  <pre><code>-(void) captureNow {
      AVCaptureConnection *videoConnection = nil;
      for (AVCaptureConnection *connection in self.stillImageOutput.connections) {
          for (AVCaptureInputPort *port in [connection inputPorts]) {
              if ([[port mediaType] isEqual:AVMediaTypeVideo] ) {
                  videoConnection = connection;
                  break;
              }
          }
          if (videoConnection) { break; }
      }
  
      __block BOOL done = NO;
  
      NSLog(@"about to request a capture from: %@", self.stillImageOutput);
      [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
          NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
          UIImage *image = [[UIImage alloc] initWithData:imageData];
          NSLog(@"image captured");
  
          done = YES;
       }];
  
      while (!done) {
          [NSThread sleepForTimeInterval:1.0];
      }
  }
  </code></pre>