Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions FastttCamera/FastttCamera.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@

#import <UIKit/UIKit.h>
#import "FastttCameraInterface.h"
#import "IFTTTDeviceOrientation.h"
#import "FastttFocus.h"
#import "CoreGraphics/CoreGraphics.h"
#import "CoreVideo/CoreVideo.h"
#import "CoreMedia/CoreMedia.h"
#import <AVFoundation/AVFoundation.h>
#import <ImageIO/ImageIO.h>
#import <QuartzCore/QuartzCore.h>
#import <MobileCoreServices/MobileCoreServices.h>

/**
* Public class for you to use to create a standard FastttCamera!
Expand Down
132 changes: 123 additions & 9 deletions FastttCamera/FastttCamera.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#import "FastttZoom.h"
#import "FastttCapturedImage+Process.h"

@interface FastttCamera () <FastttFocusDelegate, FastttZoomDelegate>
@interface FastttCamera () <FastttFocusDelegate, FastttZoomDelegate, AVCaptureFileOutputRecordingDelegate>

@property (nonatomic, strong) IFTTTDeviceOrientation *deviceOrientation;
@property (nonatomic, strong) FastttFocus *fastFocus;
Expand All @@ -25,6 +25,7 @@ @interface FastttCamera () <FastttFocusDelegate, FastttZoomDelegate>
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;
@property (nonatomic, strong) AVCaptureStillImageOutput *stillImageOutput;
@property (nonatomic, assign) BOOL deviceAuthorized;
@property(nonatomic, retain) AVCaptureMovieFileOutput *movieFileOutput;
@property (nonatomic, assign) BOOL isCapturingImage;

@end
Expand All @@ -48,7 +49,12 @@ @implementation FastttCamera
scalesImage = _scalesImage,
cameraDevice = _cameraDevice,
cameraFlashMode = _cameraFlashMode,
cameraTorchMode = _cameraTorchMode;
cameraTorchMode = _cameraTorchMode,
movieFileOutput = _movieFileOutput,
normalizesVideoOrientation = _normalizesVideoOrientation,
cropsVideoToVisibleAspectRatio = _cropsVideoToVisibleAspectRatio,
sessionPreset = _sessionPreset,
forcedDeviceOrientationForVideo = _forcedDeviceOrientationForVideo;

- (instancetype)init
{
Expand All @@ -65,12 +71,16 @@ - (instancetype)init
_maxScaledDimension = 0.f;
_maxZoomFactor = 1.f;
_normalizesImageOrientations = YES;
_normalizesVideoOrientation = YES;
_cropsVideoToVisibleAspectRatio = YES;
_returnsRotatedPreview = YES;
_interfaceRotatesWithOrientation = YES;
_fixedInterfaceOrientation = UIDeviceOrientationPortrait;
_cameraDevice = FastttCameraDeviceRear;
_cameraFlashMode = FastttCameraFlashModeOff;
_cameraTorchMode = FastttCameraTorchModeOff;
_sessionPreset = AVCaptureSessionPresetMedium;
_forcedDeviceOrientationForVideo = nil;

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillEnterForeground:)
Expand Down Expand Up @@ -302,7 +312,7 @@ - (void)setCameraDevice:(FastttCameraDevice)cameraDevice
if (_cameraDevice != cameraDevice) {
_cameraDevice = cameraDevice;

AVCaptureDeviceInput *oldInput = [_session.inputs lastObject];
AVCaptureDeviceInput *oldInput = [self _currentCameraInput];
AVCaptureDeviceInput *newInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];

[_session beginConfiguration];
Expand Down Expand Up @@ -411,7 +421,8 @@ - (void)_setupCaptureSession
dispatch_async(dispatch_get_main_queue(), ^{

_session = [AVCaptureSession new];
_session.sessionPreset = AVCaptureSessionPresetPhoto;
_session.automaticallyConfiguresApplicationAudioSession = false;
_session.sessionPreset = _sessionPreset;

AVCaptureDevice *device = [AVCaptureDevice cameraDevice:self.cameraDevice];

Expand All @@ -429,10 +440,12 @@ - (void)_setupCaptureSession
[device unlockForConfiguration];
}

[_session beginConfiguration];

#if !TARGET_IPHONE_SIMULATOR
AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
[_session addInput:deviceInput];

switch (device.position) {
case AVCaptureDevicePositionBack:
_cameraDevice = FastttCameraDeviceRear;
Expand All @@ -448,14 +461,19 @@ - (void)_setupCaptureSession

[self setCameraFlashMode:_cameraFlashMode];
#endif
NSDictionary *outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG};

NSDictionary *outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG};

_stillImageOutput = [AVCaptureStillImageOutput new];
_stillImageOutput.outputSettings = outputSettings;

[_session addOutput:_stillImageOutput];

_movieFileOutput = [AVCaptureMovieFileOutput new];
[_session addOutput:_movieFileOutput];

[_session commitConfiguration];

_deviceOrientation = [IFTTTDeviceOrientation new];

if (self.isViewLoaded && self.view.window) {
Expand Down Expand Up @@ -489,6 +507,8 @@ - (void)_teardownCaptureSession

[_session removeOutput:_stillImageOutput];
_stillImageOutput = nil;
[_session removeOutput:_movieFileOutput];
_movieFileOutput = nil;

[self _removePreviewLayer];

Expand Down Expand Up @@ -552,6 +572,87 @@ - (void)_takePhoto
#endif
}

#pragma mark - Capturing Video

- (void)startRecordingVideo {

[_session beginConfiguration];
for (AVCaptureInput *captureInput in [_session inputs]) {
BOOL isAudioInput = NO;
for (AVCaptureInputPort *port in [captureInput ports]) {
if ([[port mediaType] isEqual:AVMediaTypeAudio]) {
isAudioInput = YES;
break;
}
}

if (isAudioInput) {
[_session removeInput:captureInput];
}
}

AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
[_session addInput:audioInput];
[_session commitConfiguration];

AVCaptureConnection *videoConnection = nil;

for (AVCaptureConnection *connection in [_movieFileOutput connections]) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
videoConnection = connection;
break;
}
}

if (videoConnection) {
break;
}
}

if (self.forcedDeviceOrientationForVideo) {
[videoConnection setVideoOrientation: self.forcedDeviceOrientationForVideo];
} else if ([videoConnection isVideoOrientationSupported]) {
[videoConnection setVideoOrientation:[self _currentCaptureVideoOrientationForDevice]];
}

if ([videoConnection isVideoMirroringSupported]) {
[videoConnection setVideoMirrored:(_cameraDevice == FastttCameraDeviceFront)];
}

NSString *plistPath;
NSString *rootPath;
rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
plistPath = [rootPath stringByAppendingPathComponent:@"temp.mov"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:plistPath];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:plistPath]) {
NSError *error;

[fileManager removeItemAtPath:[fileURL absoluteString] error:&error];
}
[_movieFileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:self];
}

- (void)stopRecordingVideo {
[_movieFileOutput stopRecording];
}

#pragma mark - AVCaptureFileOutputRecordingDelegate

- (void)captureOutput:(AVCaptureFileOutput *)captureOutput
didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
fromConnections:(NSArray *)connections
error:(NSError *)error {

if ([self.delegate respondsToSelector:@selector(cameraController:didFinishRecordingVideo:)]) {
[self.delegate cameraController:self didFinishRecordingVideo:outputFileURL];
}
}

#pragma mark - Capturing

#pragma mark - Processing a Photo

- (void)_processCameraPhoto:(UIImage *)image needsPreviewRotation:(BOOL)needsPreviewRotation previewOrientation:(UIDeviceOrientation)previewOrientation
Expand Down Expand Up @@ -707,9 +808,22 @@ - (void)_checkDeviceAuthorizationWithCompletion:(void (^)(BOOL isAuthorized))com

#pragma mark - FastttCameraDevice

- (AVCaptureDeviceInput *)_currentCameraInput {
AVCaptureDeviceInput *currentCameraInput;

for (AVCaptureDeviceInput *captureInput in _session.inputs) {
NSArray<AVMediaType> *mediaTypes = [captureInput.ports valueForKey:@"mediaType"];
if ([mediaTypes containsObject:AVMediaTypeVideo]) {
currentCameraInput = captureInput;
}
}
return currentCameraInput;

}

- (AVCaptureDevice *)_currentCameraDevice
{
return [_session.inputs.lastObject device];
return [[self _currentCameraInput] device];
}

- (AVCaptureConnection *)_currentCaptureConnection
Expand Down
49 changes: 49 additions & 0 deletions FastttCamera/FastttCameraInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,26 @@
* Make sure to also set interfaceRotatesWithOrientation = YES, otherwise this property will be ignored.
*/
@property (nonatomic, assign) UIDeviceOrientation fixedInterfaceOrientation;
/**
* Defaults to YES. If this property is set to YES, the video orientation will match that of the preview video.
*/
@property(nonatomic, assign) BOOL normalizesVideoOrientation;

/**
* Defaults to YES. If this property is set to YES, the video's size will crop to that of the preview video.
*/
@property(nonatomic, assign) BOOL cropsVideoToVisibleAspectRatio;

/**
* Default to AVCaptureSessionPresetMedium.
*/

@property (nonatomic, assign) AVCaptureSessionPreset sessionPreset;

/**
* Default to nil.
*/
@property (nonatomic, assign) UIDeviceOrientation forcedDeviceOrientationForVideo;

#pragma mark - Camera State

Expand Down Expand Up @@ -222,6 +242,17 @@
*/
- (void)takePicture;

#pragma mark - Take a video!

/**
* Triggers the camera to start recording a video.
*/
- (void)startRecordingVideo;

/**
* Triggers the camera to stop recording a video.
*/
- (void)stopRecordingVideo;

#pragma mark - Process a photo

Expand Down Expand Up @@ -359,4 +390,22 @@
*/
- (void)userDeniedCameraPermissionsForCameraController:(id<FastttCameraInterface>)cameraController;

/**
* Called when the camera controller has finished recording video
*
* @param cameraController The FastttCamera instance that captured the photo.
*
* @param videoURL Location of the video without the proper cropping and orientation
*/
- (void)cameraController:(id<FastttCameraInterface>)cameraController didFinishRecordingVideo:(NSURL *)videoURL;

/**
* Called when the camera controller has finished recording video
*
* @param cameraController The FastttCamera instance that captured the photo.
*
* @param videoURL Location of the video with the proper cropping and orientation
*/
- (void)cameraController:(id<FastttCameraInterface>)cameraController didFinishNormalizedCapturedVideo:(NSURL *)videoURL;

@end