iOS provide UIIMagePickerController for getting an image from photo library and for capturing a new image. But iOS also provide a cool feature for creating custom camera. We can create custom camera using AVFoundation framework, which give direct access to the camera and microphone.
This process is managed through AVCaptureSession which coordinate the flow of data from input devices (such as camera, microphone) to outputs (Such as image and movie file).
Minimally we need:
1) An instance of AVCaptureDevice to present the input device, such as a camera and microphone.
2) An instance of a concrete subclass of AVCaptureInput to configure the ports from the input device.
3) An instance of a concrete subclass of AVCaptureOutput to manage the output to a movie file or still image.
4) An instance of AVCaptureSession to coordinate the data flow from input to output.
5) An instance of AVCaptureVideoPreviewLayer to display a preview of what the camera is recording.
Start session:
self.session = [[AVCaptureSession alloc] init]; //initialize an instance of AVCaptureSession
[self.session setSessionPreset:AVCaptureSessionPresetHigh]; //Indicates the session preset currently in use by the receiver.
Capture Device:
An AVCaptureDevice represents a physical device that provides realtime input media data, such as video and audio. A input device can be the camera or microphone.
AVCaptureDevice *inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
Capture Device Input:
AVCaptureDeviceInput is a concrete subclass of AVCaptureInput that provides an interface for capturing media from an AVCaptureDevice.
self.captureDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:&error];
Now add capture device input to session
if ( [self.session canAddInput:self.captureDeviceInput] )
[self.session addInput:self.captureDeviceInput];
Preview:
AVCaptureVideoPreviewLayer quickly render the raw data collected by the camera on the screen, means we can also say, AVCaptureVideoPreviewLayer is display a preview of what the camera is capturing.
AVCaptureVideoPreviewLayer is a subclass of CALayer that we add as a sublayer of preview view's layer.
AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
[previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
CALayer *rootLayer = [[self view] layer];
[rootLayer setMasksToBounds:YES];
[previewLayer setFrame:CGRectMake(0, 0, rootLayer.bounds.size.height, rootLayer.bounds.size.height)];
[self.PreviewView.layer insertSublayer:previewLayer atIndex:0];
Now, Its enough for display camera recording on screen.
Start the session
[self.session startRunning];
Run the app and check.
Now add a UIButton to the view for capture rendered raw data as a image.
and, for manage the output to a still image create an instance of AVCaptureStillImageOutput and add to session.
AVCaptureStillImageOutput is a concrete subclass of AVCaptureOutput that can be used to capture high-quality still images with accompanying metadata.
AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
if ([self.session canAddOutput:stillImageOutput])
{
[stillImageOutput setOutputSettings:@{AVVideoCodecKey : AVVideoCodecJPEG}];
[self.session addOutput:stillImageOutput];
[self setStillImageOutput:stillImageOutput];
}
(Add above code before start the session)
Now add button method for capture image,
-(IBAction)captureButtonAction:(id)sender{
//capture preview image
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:[[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo] completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (imageDataSampleBuffer)
{
//get image data from buffer
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
//save image to photo library (if you want to save captured image)
[[[ALAssetsLibrary alloc] init] writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:nil];
}
}];
}
Now its time to capture fresh image.
Run the app and capture image.
Now Add another method for swap camera(front to back and back to front)
#pragma mark -
-(IBAction) changeCameraAction:(id)sender{
//disable button
self.captureButton.enabled = NO;
self.swapButton.enabled = NO;
//get current input device
AVCaptureDevice *currentDevice = self.captureDeviceInput.device;
AVCaptureDevicePosition preferredPosion = AVCaptureDevicePositionUnspecified;
AVCaptureDevicePosition currentPosition = currentDevice.position
;
//get new preferred position
switch (currentPosition) {
case AVCaptureDevicePositionUnspecified:
break;
case AVCaptureDevicePositionBack:
preferredPosion = AVCaptureDevicePositionFront;
break;
case AVCaptureDevicePositionFront:
preferredPosion = AVCaptureDevicePositionBack;
break;
}//end switch case
//configure new input device
AVCaptureDevice *captureDevice = [self deviceWithMediaType:AVMediaTypeVideo withPreferredPosition:preferredPosion];
AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:nil];
//update session
[self.session beginConfiguration];
// Remove the existing device input first, since using the front and back camera simultaneously is not supported.
[self.session removeInput:self.captureDeviceInput];
if ( [self.session canAddInput:deviceInput] ) {
[self.session addInput:deviceInput];
self.captureDeviceInput = deviceInput;
}
else {
[self.session addInput:self.captureDeviceInput];
}
[self.session commitConfiguration];
//enable button
self.captureButton.enabled = YES;
self.swapButton.enabled = YES;
}
-(AVCaptureDevice *) deviceWithMediaType:(NSString *)mediaType withPreferredPosition:(AVCaptureDevicePosition) position{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:mediaType];
AVCaptureDevice *captureDevice = devices.firstObject;
for ( AVCaptureDevice *device in devices ) {
if ( device.position == position ) {
captureDevice = device;
break;
}
}
return captureDevice;
}
Click here for complete project.
This process is managed through AVCaptureSession which coordinate the flow of data from input devices (such as camera, microphone) to outputs (Such as image and movie file).
Minimally we need:
1) An instance of AVCaptureDevice to present the input device, such as a camera and microphone.
2) An instance of a concrete subclass of AVCaptureInput to configure the ports from the input device.
3) An instance of a concrete subclass of AVCaptureOutput to manage the output to a movie file or still image.
4) An instance of AVCaptureSession to coordinate the data flow from input to output.
5) An instance of AVCaptureVideoPreviewLayer to display a preview of what the camera is recording.
Start session:
self.session = [[AVCaptureSession alloc] init]; //initialize an instance of AVCaptureSession
[self.session setSessionPreset:AVCaptureSessionPresetHigh]; //Indicates the session preset currently in use by the receiver.
Capture Device:
An AVCaptureDevice represents a physical device that provides realtime input media data, such as video and audio. A input device can be the camera or microphone.
AVCaptureDevice *inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
Capture Device Input:
AVCaptureDeviceInput is a concrete subclass of AVCaptureInput that provides an interface for capturing media from an AVCaptureDevice.
self.captureDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:&error];
Now add capture device input to session
if ( [self.session canAddInput:self.captureDeviceInput] )
[self.session addInput:self.captureDeviceInput];
Preview:
AVCaptureVideoPreviewLayer quickly render the raw data collected by the camera on the screen, means we can also say, AVCaptureVideoPreviewLayer is display a preview of what the camera is capturing.
AVCaptureVideoPreviewLayer is a subclass of CALayer that we add as a sublayer of preview view's layer.
AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
[previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
CALayer *rootLayer = [[self view] layer];
[rootLayer setMasksToBounds:YES];
[previewLayer setFrame:CGRectMake(0, 0, rootLayer.bounds.size.height, rootLayer.bounds.size.height)];
[self.PreviewView.layer insertSublayer:previewLayer atIndex:0];
Now, Its enough for display camera recording on screen.
Start the session
[self.session startRunning];
Run the app and check.
Now add a UIButton to the view for capture rendered raw data as a image.
and, for manage the output to a still image create an instance of AVCaptureStillImageOutput and add to session.
AVCaptureStillImageOutput is a concrete subclass of AVCaptureOutput that can be used to capture high-quality still images with accompanying metadata.
AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
if ([self.session canAddOutput:stillImageOutput])
{
[stillImageOutput setOutputSettings:@{AVVideoCodecKey : AVVideoCodecJPEG}];
[self.session addOutput:stillImageOutput];
[self setStillImageOutput:stillImageOutput];
}
(Add above code before start the session)
Now add button method for capture image,
-(IBAction)captureButtonAction:(id)sender{
//capture preview image
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:[[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo] completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (imageDataSampleBuffer)
{
//get image data from buffer
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
//save image to photo library (if you want to save captured image)
[[[ALAssetsLibrary alloc] init] writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:nil];
}
}];
}
Now its time to capture fresh image.
Run the app and capture image.
Now Add another method for swap camera(front to back and back to front)
#pragma mark -
-(IBAction) changeCameraAction:(id)sender{
//disable button
self.captureButton.enabled = NO;
self.swapButton.enabled = NO;
//get current input device
AVCaptureDevice *currentDevice = self.captureDeviceInput.device;
AVCaptureDevicePosition preferredPosion = AVCaptureDevicePositionUnspecified;
AVCaptureDevicePosition currentPosition = currentDevice.position
;
//get new preferred position
switch (currentPosition) {
case AVCaptureDevicePositionUnspecified:
break;
case AVCaptureDevicePositionBack:
preferredPosion = AVCaptureDevicePositionFront;
break;
case AVCaptureDevicePositionFront:
preferredPosion = AVCaptureDevicePositionBack;
break;
}//end switch case
//configure new input device
AVCaptureDevice *captureDevice = [self deviceWithMediaType:AVMediaTypeVideo withPreferredPosition:preferredPosion];
AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:nil];
//update session
[self.session beginConfiguration];
// Remove the existing device input first, since using the front and back camera simultaneously is not supported.
[self.session removeInput:self.captureDeviceInput];
if ( [self.session canAddInput:deviceInput] ) {
[self.session addInput:deviceInput];
self.captureDeviceInput = deviceInput;
}
else {
[self.session addInput:self.captureDeviceInput];
}
[self.session commitConfiguration];
//enable button
self.captureButton.enabled = YES;
self.swapButton.enabled = YES;
}
-(AVCaptureDevice *) deviceWithMediaType:(NSString *)mediaType withPreferredPosition:(AVCaptureDevicePosition) position{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:mediaType];
AVCaptureDevice *captureDevice = devices.firstObject;
for ( AVCaptureDevice *device in devices ) {
if ( device.position == position ) {
captureDevice = device;
break;
}
}
return captureDevice;
}
Click here for complete project.