Skip to content

Instantly share code, notes, and snippets.

@eralston
Last active December 19, 2015 13:38
Show Gist options
  • Save eralston/5963263 to your computer and use it in GitHub Desktop.
Save eralston/5963263 to your computer and use it in GitHub Desktop.
A sub-class of AVCaptureSession that adds a few helper properties for simplifying access to device hardware and add capabilities like flipping between the front and back camera.
//
// SimpleCaptureSession.h
//
// Copyright (c) 2013 Erik Ralston
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import <AVFoundation/AVFoundation.h>
///
/// A class that adds several helpers to AVCapture session to make video recording and camera management easier
///
@interface SimpleCaptureSession : AVCaptureSession
// Devices
@property (nonatomic, readonly) AVCaptureDevice *rearCameraDevice;
@property (nonatomic, readonly) AVCaptureDevice *frontCameraDevice;
@property (nonatomic, readonly) AVCaptureDevice *audioDevice;
// Helpers
- (BOOL)isFrontCameraSupported;
// Methods for safely adding devices (and logging when things go wrong)
- (void)tryAddInput:(AVCaptureInput *)input;
- (AVCaptureDeviceInput *)tryAddDeviceAsInput:(AVCaptureDevice *)device;
// Methods for easily adding devices as inputs
- (AVCaptureDeviceInput *)addRearCameraAsInput;
- (void)removeRearCameraAsInput;
- (AVCaptureDeviceInput *)addFrontCameraAsInput;
- (void)removeFrontCameraAsInput;
- (AVCaptureDeviceInput *)addAudioAsInput;
// Methods for easily adding output
- (void)tryAddOutput:(AVCaptureOutput *)output;
- (AVCaptureMovieFileOutput *)addFileOutput;
// Methods for mixing input and output
- (void)flipCamera;
@end
//
// SimpleCaptureSession.m
//
// Copyright (c) 2013 Erik Ralston
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "SimpleCaptureSession.h"
@interface SimpleCaptureSession()
{
// Fields for holding onto inputs for devices
AVCaptureDeviceInput *_rearCameraDeviceInput;
AVCaptureDeviceInput *_frontCameraDeviceInput;
AVCaptureDeviceInput *_audioDeviceInput;
}
@end
@implementation SimpleCaptureSession
#pragma mark - Input Device Properties
///
/// Gets the rear camera device
///
- (AVCaptureDevice *)rearCameraDevice
{
return [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
}
///
/// Gets the front camera device
/// NOTE: Returns nil if no front camera found
///
- (AVCaptureDevice *)frontCameraDevice
{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for (AVCaptureDevice *device in devices) {
// Check if this is the front-facing camera
if([device position] == AVCaptureDevicePositionFront)
{
// if we found it, then add it and return it
return device;
}
}
// if we didn't find it, return nil
return nil;
}
///
/// Gets the microphone device
///
- (AVCaptureDevice *)audioDevice
{
return [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
}
#pragma mark - Helper Methods
///
/// Returns YES if the front camera is supported by the current device; otherwise, returning NO
///
- (BOOL)isFrontCameraSupported
{
return [self frontCameraDevice] != nil;
}
///
/// Attempts to add the given input, logging an error if unable
///
- (void)tryAddInput:(AVCaptureInput *)input
{
if ([self canAddInput:input])
[self addInput:input];
else
NSLog(@"Couldn't add input device %@", input);
}
///
/// Tries to add the given device as an input, logging errors if problems occur
///
- (AVCaptureDeviceInput *)tryAddDeviceAsInput:(AVCaptureDevice *)device
{
if (device) {
NSError *error;
AVCaptureDeviceInput *videoIn = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (!error) {
[self tryAddInput:videoIn];
return videoIn;
}
else
NSLog(@"Error trying to capture for device %@ with error %@", device, error);
}
else
NSLog(@"Nil device passed, could not add");
return nil;
}
///
/// Adds the video device as an input to the AVCaptureSession
///
- (AVCaptureDeviceInput *)addRearCameraAsInput
{
// Setup Video Capture
_rearCameraDeviceInput = [self tryAddDeviceAsInput:self.rearCameraDevice];
return _rearCameraDeviceInput;
}
///
/// Removes the rear camera as an input
///
- (void)removeRearCameraAsInput
{
[self removeInput:_rearCameraDeviceInput];
_rearCameraDeviceInput = nil;
}
///
/// Tries to add the front-facing camera as an input for this device,
///
- (AVCaptureDeviceInput *)addFrontCameraAsInput
{
// Try to find the front facing camera
AVCaptureDevice *frontFacingCameraDevice = [self frontCameraDevice];
// If we have a front-facing camera, then add it; otherwise, add the read camera
if(frontFacingCameraDevice)
_frontCameraDeviceInput = [self tryAddDeviceAsInput:frontFacingCameraDevice];
else
_frontCameraDeviceInput = [self addRearCameraAsInput];
return _frontCameraDeviceInput;
}
///
/// Removes the front camera as an input
///
- (void)removeFrontCameraAsInput
{
[self removeInput:_frontCameraDeviceInput];
_frontCameraDeviceInput = nil;
}
///
/// Adds the audio device as an input to the AVCaptureSession
///
- (AVCaptureDeviceInput *)addAudioAsInput
{
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
return [self tryAddDeviceAsInput:audioDevice];
}
#pragma mark - Methods for Easy Output
///
/// Adds an output device, only if able, then logging if failed
///
- (void)tryAddOutput:(AVCaptureOutput *)output
{
if([self canAddOutput:output])
[self addOutput:output];
else
NSLog(@"Unable to add output %@", output);
}
///
/// Adds a capture movie file output to the current session
///
- (AVCaptureMovieFileOutput *)addFileOutput
{
AVCaptureMovieFileOutput *movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
[self tryAddOutput:movieFileOutput];
return movieFileOutput;
}
#pragma mark - Methods for Input & Output
///
/// Flips the front and rear-facing camera, based on which one is currently in use
///
- (void)flipCamera
{
if(_frontCameraDeviceInput)
{
[self removeFrontCameraAsInput];
[self addRearCameraAsInput];
} else {
[self removeRearCameraAsInput];
[self addFrontCameraAsInput];
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment