From dd021e0eda9f476727f3953c1f288986614dad5b Mon Sep 17 00:00:00 2001 From: Justin Khan Date: Tue, 24 Mar 2015 12:35:42 -0400 Subject: [PATCH 01/15] Added video output and audio input Added start and stop video recording with delegate method --- .clang-format | 52 ++++ FastttCamera/FastttCamera.h | 5 +- FastttCamera/FastttCamera.m | 477 ++++++++++++++++++------------------ FastttVideoCamera.h | 13 + FastttVideoCamera.m | 18 ++ 5 files changed, 319 insertions(+), 246 deletions(-) create mode 100644 .clang-format create mode 100644 FastttVideoCamera.h create mode 100644 FastttVideoCamera.m diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..141599e --- /dev/null +++ b/.clang-format @@ -0,0 +1,52 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +ConstructorInitializerIndentWidth: 4 +AlignEscapedNewlinesLeft: false +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortFunctionsOnASingleLine: true +AlwaysBreakTemplateDeclarations: false +AlwaysBreakBeforeMultilineStrings: false +BreakBeforeBinaryOperators: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BinPackParameters: true +ColumnLimit: 160 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +DerivePointerBinding: false +ExperimentalAutoDetectBinPacking: false +IndentCaseLabels: false +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakString: 1000 +PenaltyBreakFirstLessLess: 120 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerBindsToType: false +SpacesBeforeTrailingComments: 1 +Cpp11BracedListStyle: true +Standard: Cpp11 +IndentWidth: 4 +TabWidth: 8 +UseTab: Never +BreakBeforeBraces: Attach +IndentFunctionDeclarationAfterType: false +SpacesInParentheses: false +SpacesInAngles: false +SpaceInEmptyParentheses: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: true +SpaceBeforeAssignmentOperators: true +ContinuationIndentWidth: 4 +CommentPragmas: '^ IWYU pragma:' +SpaceBeforeParens: ControlStatements +... + diff --git a/FastttCamera/FastttCamera.h b/FastttCamera/FastttCamera.h index c4f028f..d2ee85d 100644 --- a/FastttCamera/FastttCamera.h +++ b/FastttCamera/FastttCamera.h @@ -7,7 +7,10 @@ // @import UIKit; + #import "FastttCameraInterface.h" +#import "IFTTTDeviceOrientation.h" +#import "FastttFocus.h" /** * Public class for you to use to create a standard FastttCamera! @@ -18,6 +21,6 @@ * @note If you want to use filters with your live camera preview, * use an instance of FastttFilterCamera instead. */ -@interface FastttCamera : UIViewController +@interface FastttCamera : UIViewController @end diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index 3f2edb4..36fd757 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -9,43 +9,34 @@ @import AVFoundation; #import "FastttCamera.h" -#import "IFTTTDeviceOrientation.h" #import "UIImage+FastttCamera.h" #import "AVCaptureDevice+FastttCamera.h" -#import "FastttFocus.h" #import "FastttCapturedImage+Process.h" @interface FastttCamera () -@property (nonatomic, strong) IFTTTDeviceOrientation *deviceOrientation; -@property (nonatomic, strong) FastttFocus *fastFocus; -@property (nonatomic, strong) AVCaptureSession *session; -@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer; -@property (nonatomic, strong) AVCaptureStillImageOutput *stillImageOutput; -@property (nonatomic, assign) BOOL deviceAuthorized; +@property(nonatomic, strong) IFTTTDeviceOrientation *deviceOrientation; +@property(nonatomic, strong) FastttFocus *fastFocus; +@property(nonatomic, strong) AVCaptureSession *session; +@property(nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer; +@property(nonatomic, strong) AVCaptureStillImageOutput *stillImageOutput; +@property(nonatomic, retain) AVCaptureMovieFileOutput *movieFileOutput; +@property(nonatomic, assign) BOOL deviceAuthorized; @end @implementation FastttCamera -@synthesize delegate = _delegate, - returnsRotatedPreview = _returnsRotatedPreview, - showsFocusView = _showsFocusView, - maxScaledDimension = _maxScaledDimension, - normalizesImageOrientations = _normalizesImageOrientations, - cropsImageToVisibleAspectRatio = _cropsImageToVisibleAspectRatio, - interfaceRotatesWithOrientation = _interfaceRotatesWithOrientation, - handlesTapFocus = _handlesTapFocus, - scalesImage = _scalesImage, - cameraDevice = _cameraDevice, - cameraFlashMode = _cameraFlashMode; - -- (instancetype)init -{ +@synthesize delegate = _delegate, returnsRotatedPreview = _returnsRotatedPreview, showsFocusView = _showsFocusView, maxScaledDimension = _maxScaledDimension, + normalizesImageOrientations = _normalizesImageOrientations, cropsImageToVisibleAspectRatio = _cropsImageToVisibleAspectRatio, + interfaceRotatesWithOrientation = _interfaceRotatesWithOrientation, handlesTapFocus = _handlesTapFocus, scalesImage = _scalesImage, + cameraDevice = _cameraDevice, cameraFlashMode = _cameraFlashMode, movieFileOutput = _movieFileOutput; + +- (instancetype)init { if ((self = [super init])) { - + [self _setupCaptureSession]; - + _handlesTapFocus = YES; _showsFocusView = YES; _cropsImageToVisibleAspectRatio = YES; @@ -56,87 +47,80 @@ - (instancetype)init _interfaceRotatesWithOrientation = YES; _cameraDevice = FastttCameraDeviceRear; _cameraFlashMode = FastttCameraFlashModeOff; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; } - + return self; } -- (void)dealloc -{ +- (void)dealloc { _fastFocus = nil; - + [self _teardownCaptureSession]; - + [[NSNotificationCenter defaultCenter] removeObserver:self]; } #pragma mark - View Events -- (void)viewDidLoad -{ +- (void)viewDidLoad { [super viewDidLoad]; - + [self _insertPreviewLayer]; - + _fastFocus = [FastttFocus fastttFocusWithView:self.view]; self.fastFocus.delegate = self; - + if (!self.handlesTapFocus) { self.fastFocus.detectsTaps = NO; } } -- (void)viewWillAppear:(BOOL)animated -{ +- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - + [self _startRunning]; - + [self _insertPreviewLayer]; - + [self _setPreviewVideoOrientation]; } -- (void)viewDidDisappear:(BOOL)animated -{ +- (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; - + [self _stopRunning]; } -- (void)viewDidLayoutSubviews -{ +- (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; _previewLayer.frame = self.view.layer.bounds; } -- (void)applicationWillEnterForeground:(NSNotification *)notification -{ +- (void)applicationWillEnterForeground:(NSNotification *)notification { [self _setupCaptureSession]; } -- (void)applicationDidBecomeActive:(NSNotification *)notification -{ +- (void)applicationDidBecomeActive:(NSNotification *)notification { if (self.isViewLoaded && self.view.window) { [self _startRunning]; [self _insertPreviewLayer]; @@ -144,244 +128,227 @@ - (void)applicationDidBecomeActive:(NSNotification *)notification } } -- (void)applicationWillResignActive:(NSNotification *)notification -{ +- (void)applicationWillResignActive:(NSNotification *)notification { [self _stopRunning]; } -- (void)applicationDidEnterBackground:(NSNotification *)notification -{ +- (void)applicationDidEnterBackground:(NSNotification *)notification { [self _teardownCaptureSession]; } #pragma mark - Autorotation -- (NSUInteger)supportedInterfaceOrientations -{ +- (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskAll; } -- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration -{ +- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [self _setPreviewVideoOrientation]; } #pragma mark - Taking a Photo -- (void)takePicture -{ +- (void)takePicture { if (!_deviceAuthorized) { return; } - + [self _takePhoto]; } #pragma mark - Processing a Photo -- (void)processImage:(UIImage *)image withMaxDimension:(CGFloat)maxDimension -{ +- (void)processImage:(UIImage *)image withMaxDimension:(CGFloat)maxDimension { [self _processImage:image withCropRect:CGRectNull maxDimension:maxDimension fromCamera:NO needsPreviewRotation:NO]; } -- (void)processImage:(UIImage *)image withCropRect:(CGRect)cropRect -{ +- (void)processImage:(UIImage *)image withCropRect:(CGRect)cropRect { [self _processImage:image withCropRect:cropRect maxDimension:0.f fromCamera:NO needsPreviewRotation:NO]; } -- (void)processImage:(UIImage *)image withCropRect:(CGRect)cropRect maxDimension:(CGFloat)maxDimension -{ +- (void)processImage:(UIImage *)image withCropRect:(CGRect)cropRect maxDimension:(CGFloat)maxDimension { [self _processImage:image withCropRect:cropRect maxDimension:maxDimension fromCamera:NO needsPreviewRotation:NO]; } #pragma mark - Camera State -+ (BOOL)isPointFocusAvailableForCameraDevice:(FastttCameraDevice)cameraDevice -{ ++ (BOOL)isPointFocusAvailableForCameraDevice:(FastttCameraDevice)cameraDevice { return [AVCaptureDevice isPointFocusAvailableForCameraDevice:cameraDevice]; } -- (void)focusAtPoint:(CGPoint)touchPoint -{ +- (void)focusAtPoint:(CGPoint)touchPoint { CGPoint pointOfInterest = [self _focusPointOfInterestForTouchPoint:touchPoint]; - + [self _focusAtPointOfInterest:pointOfInterest]; } -- (BOOL)isFlashAvailableForCurrentDevice -{ +- (BOOL)isFlashAvailableForCurrentDevice { AVCaptureDevice *device = [self _currentCameraDevice]; - + if ([device isFlashModeSupported:AVCaptureFlashModeOn]) { return YES; } - + return NO; } -+ (BOOL)isFlashAvailableForCameraDevice:(FastttCameraDevice)cameraDevice -{ ++ (BOOL)isFlashAvailableForCameraDevice:(FastttCameraDevice)cameraDevice { return [AVCaptureDevice isFlashAvailableForCameraDevice:cameraDevice]; } -+ (BOOL)isCameraDeviceAvailable:(FastttCameraDevice)cameraDevice -{ ++ (BOOL)isCameraDeviceAvailable:(FastttCameraDevice)cameraDevice { return ([AVCaptureDevice cameraDevice:cameraDevice] != nil); } -- (void)setCameraDevice:(FastttCameraDevice)cameraDevice -{ +- (void)setCameraDevice:(FastttCameraDevice)cameraDevice { AVCaptureDevice *device = [AVCaptureDevice cameraDevice:cameraDevice]; - + if (!device) { return; } - + if (_cameraDevice != cameraDevice) { _cameraDevice = cameraDevice; - + AVCaptureDeviceInput *oldInput = [_session.inputs lastObject]; AVCaptureDeviceInput *newInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil]; - + [_session beginConfiguration]; [_session removeInput:oldInput]; [_session addInput:newInput]; [_session commitConfiguration]; } - + [self setCameraFlashMode:_cameraFlashMode]; } -- (void)setCameraFlashMode:(FastttCameraFlashMode)cameraFlashMode -{ +- (void)setCameraFlashMode:(FastttCameraFlashMode)cameraFlashMode { AVCaptureDevice *device = [self _currentCameraDevice]; - + if ([AVCaptureDevice isFlashAvailableForCameraDevice:self.cameraDevice]) { _cameraFlashMode = cameraFlashMode; [device setCameraFlashMode:cameraFlashMode]; return; } - + _cameraFlashMode = FastttCameraFlashModeOff; } #pragma mark - Capture Session Management -- (void)_startRunning -{ +- (void)_startRunning { if (![_session isRunning]) { [_session startRunning]; } } -- (void)_stopRunning -{ +- (void)_stopRunning { if ([_session isRunning]) { [_session stopRunning]; } } -- (void)_insertPreviewLayer -{ +- (void)_insertPreviewLayer { if (!_deviceAuthorized) { return; } - - if ([_previewLayer superlayer] == [self.view layer] - && [_previewLayer session] == _session) { + + if ([_previewLayer superlayer] == [self.view layer] && [_previewLayer session] == _session) { return; } - + [self _removePreviewLayer]; - + CALayer *rootLayer = [self.view layer]; rootLayer.masksToBounds = YES; - + _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_session]; _previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; - + _previewLayer.frame = rootLayer.bounds; - + [rootLayer insertSublayer:_previewLayer atIndex:0]; } -- (void)_removePreviewLayer -{ +- (void)_removePreviewLayer { [_previewLayer removeFromSuperlayer]; _previewLayer = nil; } -- (void)_setupCaptureSession -{ +- (void)_setupCaptureSession { if (_session) { return; } - + #if !TARGET_IPHONE_SIMULATOR [self _checkDeviceAuthorizationWithCompletion:^(BOOL isAuthorized) { - + _deviceAuthorized = isAuthorized; #else - _deviceAuthorized = YES; + _deviceAuthorized = YES; #endif if (!_deviceAuthorized && [self.delegate respondsToSelector:@selector(userDeniedCameraPermissionsForCameraController:)]) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self.delegate userDeniedCameraPermissionsForCameraController:self]; - }); + dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate userDeniedCameraPermissionsForCameraController:self]; }); } - + if (_deviceAuthorized) { - + dispatch_async(dispatch_get_main_queue(), ^{ - + _session = [AVCaptureSession new]; _session.sessionPreset = AVCaptureSessionPresetPhoto; - + AVCaptureDevice *device = [AVCaptureDevice cameraDevice:self.cameraDevice]; - + if (!device) { device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; } - + if ([device lockForConfiguration:nil]) { - if([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]){ + if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) { device.focusMode = AVCaptureFocusModeContinuousAutoFocus; } - + device.exposureMode = AVCaptureExposureModeContinuousAutoExposure; - + [device unlockForConfiguration]; } #if !TARGET_IPHONE_SIMULATOR AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil]; [_session addInput:deviceInput]; - + + AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; + AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil]; + [_session addInput:audioInput]; + switch (device.position) { - case AVCaptureDevicePositionBack: - _cameraDevice = FastttCameraDeviceRear; - break; - - case AVCaptureDevicePositionFront: - _cameraDevice = FastttCameraDeviceFront; - break; - - default: - break; + case AVCaptureDevicePositionBack: + _cameraDevice = FastttCameraDeviceRear; + break; + + case AVCaptureDevicePositionFront: + _cameraDevice = FastttCameraDeviceFront; + break; + + default: + break; } - + [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]; + _deviceOrientation = [IFTTTDeviceOrientation new]; - + if (self.isViewLoaded && self.view.window) { [self _startRunning]; [self _insertPreviewLayer]; @@ -394,38 +361,36 @@ - (void)_setupCaptureSession #endif } -- (void)_teardownCaptureSession -{ +- (void)_teardownCaptureSession { if (!_session) { return; } - + _deviceOrientation = nil; - + if ([_session isRunning]) { [_session stopRunning]; } - + for (AVCaptureDeviceInput *input in [_session inputs]) { [_session removeInput:input]; } - + [_session removeOutput:_stillImageOutput]; _stillImageOutput = nil; - + [self _removePreviewLayer]; - + _session = nil; } #pragma mark - Capturing a Photo -- (void)_takePhoto -{ +- (void)_takePhoto { BOOL needsPreviewRotation = ![self.deviceOrientation deviceOrientationMatchesInterfaceOrientation]; - + AVCaptureConnection *videoConnection = nil; - + for (AVCaptureConnection *connection in [_stillImageOutput connections]) { for (AVCaptureInputPort *port in [connection inputPorts]) { if ([[port mediaType] isEqual:AVMediaTypeVideo]) { @@ -433,20 +398,20 @@ - (void)_takePhoto break; } } - + if (videoConnection) { break; } } - + if ([videoConnection isVideoOrientationSupported]) { [videoConnection setVideoOrientation:[self _currentCaptureVideoOrientationForDevice]]; } - + if ([videoConnection isVideoMirroringSupported]) { [videoConnection setVideoMirrored:(_cameraDevice == FastttCameraDeviceFront)]; } - + #if TARGET_IPHONE_SIMULATOR [self _insertPreviewLayer]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @@ -454,76 +419,106 @@ - (void)_takePhoto [self _processCameraPhoto:fakeImage needsPreviewRotation:needsPreviewRotation]; }); #else - [_stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection - completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) - { - if (!imageDataSampleBuffer) { - return; - } - - NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - - UIImage *image = [UIImage imageWithData:imageData]; - - [self _processCameraPhoto:image needsPreviewRotation:needsPreviewRotation]; - }); - }]; + [_stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection + completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) { + if (!imageDataSampleBuffer) { + return; + } + + NSData *imageData = + [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + UIImage *image = [UIImage imageWithData:imageData]; + + [self _processCameraPhoto:image needsPreviewRotation:needsPreviewRotation]; + }); + }]; #endif } +#pragma mark - Capturing Video + +- (void)startRecordingVideo { + + NSString *plistPath; + NSString *rootPath; + rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + plistPath = [rootPath stringByAppendingPathComponent:@"test.mov"]; + NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:plistPath]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:plistPath]) { + // @TODO: REMOVE VIDEO if there's something at that path + } + [_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 { + + NSLog(@"OUTPUTURL: %@", outputFileURL); +} + +#pragma mark - Capturing + #pragma mark - Processing a Photo -- (void)_processCameraPhoto:(UIImage *)image needsPreviewRotation:(BOOL)needsPreviewRotation -{ +- (void)_processCameraPhoto:(UIImage *)image needsPreviewRotation:(BOOL)needsPreviewRotation { CGRect cropRect = CGRectNull; if (self.cropsImageToVisibleAspectRatio) { cropRect = [image fastttCropRectFromPreviewLayer:_previewLayer]; } - - [self _processImage:image withCropRect:cropRect maxDimension:self.maxScaledDimension fromCamera:YES needsPreviewRotation:(needsPreviewRotation || !self.interfaceRotatesWithOrientation)]; + + [self _processImage:image + withCropRect:cropRect + maxDimension:self.maxScaledDimension + fromCamera:YES + needsPreviewRotation:(needsPreviewRotation || !self.interfaceRotatesWithOrientation)]; } -- (void)_processImage:(UIImage *)image withCropRect:(CGRect)cropRect maxDimension:(CGFloat)maxDimension fromCamera:(BOOL)fromCamera needsPreviewRotation:(BOOL)needsPreviewRotation -{ +- (void)_processImage:(UIImage *)image + withCropRect:(CGRect)cropRect + maxDimension:(CGFloat)maxDimension + fromCamera:(BOOL)fromCamera + needsPreviewRotation:(BOOL)needsPreviewRotation { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - + FastttCapturedImage *capturedImage = [FastttCapturedImage fastttCapturedFullImage:image]; - + [capturedImage cropToRect:cropRect returnsPreview:(fromCamera && self.returnsRotatedPreview) needsPreviewRotation:needsPreviewRotation - withCallback:^(FastttCapturedImage *capturedImage){ + withCallback:^(FastttCapturedImage *capturedImage) { if ([self.delegate respondsToSelector:@selector(cameraController:didFinishCapturingImage:)]) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self.delegate cameraController:self didFinishCapturingImage:capturedImage]; - }); + dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate cameraController:self didFinishCapturingImage:capturedImage]; }); } }]; - - void (^scaleCallback)(FastttCapturedImage *capturedImage) = ^(FastttCapturedImage *capturedImage) { + + void (^scaleCallback)(FastttCapturedImage * capturedImage) = ^(FastttCapturedImage *capturedImage) { if ([self.delegate respondsToSelector:@selector(cameraController:didFinishScalingCapturedImage:)]) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self.delegate cameraController:self didFinishScalingCapturedImage:capturedImage]; - }); + dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate cameraController:self didFinishScalingCapturedImage:capturedImage]; }); } }; - + if (maxDimension > 0.f) { - [capturedImage scaleToMaxDimension:maxDimension - withCallback:scaleCallback]; + [capturedImage scaleToMaxDimension:maxDimension withCallback:scaleCallback]; } else if (fromCamera && self.scalesImage) { - [capturedImage scaleToSize:self.view.bounds.size - withCallback:scaleCallback]; + [capturedImage scaleToSize:self.view.bounds.size withCallback:scaleCallback]; } - + if (self.normalizesImageOrientations) { - [capturedImage normalizeWithCallback:^(FastttCapturedImage *capturedImage){ + [capturedImage normalizeWithCallback:^(FastttCapturedImage *capturedImage) { if ([self.delegate respondsToSelector:@selector(cameraController:didFinishNormalizingCapturedImage:)]) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self.delegate cameraController:self didFinishNormalizingCapturedImage:capturedImage]; - }); + dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate cameraController:self didFinishNormalizingCapturedImage:capturedImage]; }); } }]; } @@ -532,86 +527,78 @@ - (void)_processImage:(UIImage *)image withCropRect:(CGRect)cropRect maxDimensio #pragma mark - AV Orientation -- (void)_setPreviewVideoOrientation -{ +- (void)_setPreviewVideoOrientation { AVCaptureConnection *videoConnection = [_previewLayer connection]; - + if ([videoConnection isVideoOrientationSupported]) { [videoConnection setVideoOrientation:[self _currentPreviewVideoOrientationForDevice]]; } } -- (AVCaptureVideoOrientation)_currentCaptureVideoOrientationForDevice -{ +- (AVCaptureVideoOrientation)_currentCaptureVideoOrientationForDevice { return [self.class _videoOrientationForDeviceOrientation:self.deviceOrientation.orientation]; } -- (AVCaptureVideoOrientation)_currentPreviewVideoOrientationForDevice -{ +- (AVCaptureVideoOrientation)_currentPreviewVideoOrientationForDevice { return [self.class _videoOrientationForDeviceOrientation:[[UIDevice currentDevice] orientation]]; } -+ (AVCaptureVideoOrientation)_videoOrientationForDeviceOrientation:(UIDeviceOrientation)deviceOrientation -{ ++ (AVCaptureVideoOrientation)_videoOrientationForDeviceOrientation:(UIDeviceOrientation)deviceOrientation { switch (deviceOrientation) { - case UIDeviceOrientationPortrait: - return AVCaptureVideoOrientationPortrait; - - case UIDeviceOrientationPortraitUpsideDown: - return AVCaptureVideoOrientationPortraitUpsideDown; - - case UIDeviceOrientationLandscapeLeft: - return AVCaptureVideoOrientationLandscapeRight; - - case UIDeviceOrientationLandscapeRight: - return AVCaptureVideoOrientationLandscapeLeft; - - default: - break; + case UIDeviceOrientationPortrait: + return AVCaptureVideoOrientationPortrait; + + case UIDeviceOrientationPortraitUpsideDown: + return AVCaptureVideoOrientationPortraitUpsideDown; + + case UIDeviceOrientationLandscapeLeft: + return AVCaptureVideoOrientationLandscapeRight; + + case UIDeviceOrientationLandscapeRight: + return AVCaptureVideoOrientationLandscapeLeft; + + default: + break; } - + return AVCaptureVideoOrientationPortrait; } #pragma mark - Camera Permissions -- (void)_checkDeviceAuthorizationWithCompletion:(void (^)(BOOL isAuthorized))completion -{ - [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { - if (completion) { - completion(granted); - } - }]; +- (void)_checkDeviceAuthorizationWithCompletion:(void (^)(BOOL isAuthorized))completion { + [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo + completionHandler:^(BOOL granted) { + if (completion) { + completion(granted); + } + }]; } #pragma mark - FastttCameraDevice -- (AVCaptureDevice *)_currentCameraDevice -{ +- (AVCaptureDevice *)_currentCameraDevice { return [_session.inputs.lastObject device]; } -- (CGPoint)_focusPointOfInterestForTouchPoint:(CGPoint)touchPoint -{ +- (CGPoint)_focusPointOfInterestForTouchPoint:(CGPoint)touchPoint { return [_previewLayer captureDevicePointOfInterestForPoint:touchPoint]; } -- (BOOL)_focusAtPointOfInterest:(CGPoint)pointOfInterest -{ +- (BOOL)_focusAtPointOfInterest:(CGPoint)pointOfInterest { return [[self _currentCameraDevice] focusAtPointOfInterest:pointOfInterest]; } #pragma mark - FastttFocusDelegate -- (BOOL)handleTapFocusAtPoint:(CGPoint)touchPoint -{ +- (BOOL)handleTapFocusAtPoint:(CGPoint)touchPoint { if ([AVCaptureDevice isPointFocusAvailableForCameraDevice:self.cameraDevice]) { - + CGPoint pointOfInterest = [self _focusPointOfInterestForTouchPoint:touchPoint]; - + return ([self _focusAtPointOfInterest:pointOfInterest] && self.showsFocusView); } - + return NO; } diff --git a/FastttVideoCamera.h b/FastttVideoCamera.h new file mode 100644 index 0000000..dd2fa2f --- /dev/null +++ b/FastttVideoCamera.h @@ -0,0 +1,13 @@ +// +// FastttVideoCamera.h +// Pods +// +// Created by Justin Khan on 2015-03-24. +// +// + +#import "FastttCamera.h" + +@interface FastttVideoCamera : FastttCamera + +@end diff --git a/FastttVideoCamera.m b/FastttVideoCamera.m new file mode 100644 index 0000000..87bbe20 --- /dev/null +++ b/FastttVideoCamera.m @@ -0,0 +1,18 @@ +// +// FastttVideoCamera.m +// Pods +// +// Created by Justin Khan on 2015-03-24. +// +// + +#import "FastttVideoCamera.h" + +@interface FastttVideoCamera () + +@end + +@implementation FastttVideoCamera + + +@end From 86308dda48306feb268bdeee87161f5de8a14bd4 Mon Sep 17 00:00:00 2001 From: Justin Khan Date: Tue, 24 Mar 2015 12:45:07 -0400 Subject: [PATCH 02/15] Added video recording methods to interface --- FastttCamera/FastttCameraInterface.h | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/FastttCamera/FastttCameraInterface.h b/FastttCamera/FastttCameraInterface.h index ab7f3d8..8e28693 100644 --- a/FastttCamera/FastttCameraInterface.h +++ b/FastttCamera/FastttCameraInterface.h @@ -18,8 +18,7 @@ /** * The delegate of the FastttCamera instance. */ -@property (nonatomic, weak) id delegate; - +@property(nonatomic, weak) id delegate; #pragma mark - Advanced Configuration Options @@ -28,13 +27,13 @@ * FastttCamera to manage tap-to-focus with its internal tap gesture recognizer. * You can still send it manual focusAtPoint: calls from your own gesture recognizer. */ -@property (nonatomic, assign) BOOL handlesTapFocus; +@property(nonatomic, assign) BOOL handlesTapFocus; /** * Default is YES. Set this to NO if you don't want the focus square to show when * the camera is focusing at a point. */ -@property (nonatomic, assign) BOOL showsFocusView; +@property(nonatomic, assign) BOOL showsFocusView; /** * Defaults to YES. Set this to NO if you want FastttCamera to return the full image @@ -44,7 +43,7 @@ * cameraController:didFinishNormalizingCapturedImage: is the only other method that will * be called, and only if normalizesImageOrientations == YES. */ -@property (nonatomic, assign) BOOL cropsImageToVisibleAspectRatio; +@property(nonatomic, assign) BOOL cropsImageToVisibleAspectRatio; /** * Defaults to YES. Set this to NO if you don't want FastttCamera to return a scaled version of the @@ -52,14 +51,14 @@ * FastttCapturedImage object, and will trigger the cameraController:didFinishScalingCapturedImage: * delegate method when it is available. */ -@property (nonatomic, assign) BOOL scalesImage; +@property(nonatomic, assign) BOOL scalesImage; /** * Defaults to scaling the cropped image to fit within the size of the camera preview. If you'd like to * set an explicit max dimension for scaling the image, set it here. This can be useful if you have specific * requirements for uploading the image. */ -@property (nonatomic, assign) CGFloat maxScaledDimension; +@property(nonatomic, assign) CGFloat maxScaledDimension; /** * Defaults to YES. Set this to NO if you would like to only use the images initially returned by FastttCamera @@ -68,32 +67,31 @@ * processing in the background, and the cameraController:didFinishNormalizingCapturedImage: delegate method will * notify you that they are ready. */ -@property (nonatomic, assign) BOOL normalizesImageOrientations; +@property(nonatomic, assign) BOOL normalizesImageOrientations; /** * Defaults to YES. Set this to NO if you don't want to display the captured image preview to the user in the same orientation * that it was captured, or if you are already rotating your interface to account for this. */ -@property (nonatomic, assign) BOOL returnsRotatedPreview; +@property(nonatomic, assign) BOOL returnsRotatedPreview; /** * Defaults to YES. Set this to NO if your interface does not autorotate with device orientation to make sure that preview * images are still displayed correctly when orientation lock is off but your interface stays in portrait. */ -@property (nonatomic, assign) BOOL interfaceRotatesWithOrientation; - +@property(nonatomic, assign) BOOL interfaceRotatesWithOrientation; #pragma mark - Camera State /** * The current camera device. */ -@property (nonatomic, assign) FastttCameraDevice cameraDevice; +@property(nonatomic, assign) FastttCameraDevice cameraDevice; /** * The current flash mode. */ -@property (nonatomic, assign) FastttCameraFlashMode cameraFlashMode; +@property(nonatomic, assign) FastttCameraFlashMode cameraFlashMode; /** * Check if flash is available for the current camera device. @@ -136,7 +134,6 @@ */ - (void)focusAtPoint:(CGPoint)touchPoint; - #pragma mark - Take a picture! /** @@ -144,6 +141,10 @@ */ - (void)takePicture; +#pragma mark - Take a video!!!! + +- (void)startRecordingVideo; +- (void)stopRecordingVideo; #pragma mark - Process a photo @@ -185,7 +186,6 @@ @end - #pragma mark - FastttCameraDelegate @protocol FastttCameraDelegate From bab6802251d274dd127b603e03022ee0d181f8de Mon Sep 17 00:00:00 2001 From: Justin Khan Date: Tue, 24 Mar 2015 13:07:22 -0400 Subject: [PATCH 03/15] Added being and commit configuration --- FastttCamera/FastttCamera.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index 36fd757..d847351 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -338,6 +338,8 @@ - (void)_setupCaptureSession { [self setCameraFlashMode:_cameraFlashMode]; #endif + [_session beginConfiguration]; + NSDictionary *outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG}; _stillImageOutput = [AVCaptureStillImageOutput new]; @@ -347,6 +349,8 @@ - (void)_setupCaptureSession { _movieFileOutput = [AVCaptureMovieFileOutput new]; [_session addOutput:_movieFileOutput]; + [_session commitConfiguration]; + _deviceOrientation = [IFTTTDeviceOrientation new]; if (self.isViewLoaded && self.view.window) { From b8470a9e326f83bf5d8333e427d47e6ddeb1e0a4 Mon Sep 17 00:00:00 2001 From: Justin Khan Date: Tue, 24 Mar 2015 13:24:39 -0400 Subject: [PATCH 04/15] Changed session's preset --- FastttCamera/FastttCamera.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index d847351..2ff420f 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -296,7 +296,7 @@ - (void)_setupCaptureSession { dispatch_async(dispatch_get_main_queue(), ^{ _session = [AVCaptureSession new]; - _session.sessionPreset = AVCaptureSessionPresetPhoto; + _session.sessionPreset = AVCaptureSessionPresetMedium; AVCaptureDevice *device = [AVCaptureDevice cameraDevice:self.cameraDevice]; @@ -454,6 +454,9 @@ - (void)startRecordingVideo { NSFileManager *fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:plistPath]) { // @TODO: REMOVE VIDEO if there's something at that path + NSError *error; + + [fileManager removeItemAtPath:[fileURL absoluteString] error:&error]; } [_movieFileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:self]; } From 3ac68be77a235dbebfe68d623fe8a5bb528d070c Mon Sep 17 00:00:00 2001 From: Justin Khan Date: Tue, 24 Mar 2015 13:46:13 -0400 Subject: [PATCH 05/15] Added delegate method when video is finished recording --- FastttCamera/FastttCamera.h | 9 ++++++++- FastttCamera/FastttCamera.m | 9 +++++---- FastttCamera/FastttCameraInterface.h | 18 +++++++++++++++++- FastttVideoCamera.h | 13 ------------- FastttVideoCamera.m | 18 ------------------ 5 files changed, 30 insertions(+), 37 deletions(-) delete mode 100644 FastttVideoCamera.h delete mode 100644 FastttVideoCamera.m diff --git a/FastttCamera/FastttCamera.h b/FastttCamera/FastttCamera.h index d2ee85d..768a5c7 100644 --- a/FastttCamera/FastttCamera.h +++ b/FastttCamera/FastttCamera.h @@ -11,6 +11,13 @@ #import "FastttCameraInterface.h" #import "IFTTTDeviceOrientation.h" #import "FastttFocus.h" +#import "CoreGraphics/CoreGraphics.h" +#import "CoreVideo/CoreVideo.h" +#import "CoreMedia/CoreMedia.h" +#import +#import +#import +#import /** * Public class for you to use to create a standard FastttCamera! @@ -21,6 +28,6 @@ * @note If you want to use filters with your live camera preview, * use an instance of FastttFilterCamera instead. */ -@interface FastttCamera : UIViewController +@interface FastttCamera : UIViewController @end diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index 2ff420f..aaec3bd 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -13,7 +13,7 @@ #import "AVCaptureDevice+FastttCamera.h" #import "FastttCapturedImage+Process.h" -@interface FastttCamera () +@interface FastttCamera () @property(nonatomic, strong) IFTTTDeviceOrientation *deviceOrientation; @property(nonatomic, strong) FastttFocus *fastFocus; @@ -449,11 +449,10 @@ - (void)startRecordingVideo { NSString *plistPath; NSString *rootPath; rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - plistPath = [rootPath stringByAppendingPathComponent:@"test.mov"]; + plistPath = [rootPath stringByAppendingPathComponent:@"temp.mov"]; NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:plistPath]; NSFileManager *fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:plistPath]) { - // @TODO: REMOVE VIDEO if there's something at that path NSError *error; [fileManager removeItemAtPath:[fileURL absoluteString] error:&error]; @@ -472,7 +471,9 @@ - (void)captureOutput:(AVCaptureFileOutput *)captureOutput fromConnections:(NSArray *)connections error:(NSError *)error { - NSLog(@"OUTPUTURL: %@", outputFileURL); + if ([self.delegate respondsToSelector:@selector(cameraController:didFinishRecordingVideo:)]) { + [self.delegate cameraController:self didFinishRecordingVideo:outputFileURL]; + } } #pragma mark - Capturing diff --git a/FastttCamera/FastttCameraInterface.h b/FastttCamera/FastttCameraInterface.h index 8e28693..7eb6091 100644 --- a/FastttCamera/FastttCameraInterface.h +++ b/FastttCamera/FastttCameraInterface.h @@ -141,9 +141,16 @@ */ - (void)takePicture; -#pragma mark - Take a video!!!! +#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 @@ -250,4 +257,13 @@ */ - (void)userDeniedCameraPermissionsForCameraController:(id)cameraController; +/** + * Called when the camera controller has finished recording video + * + * @param cameraController The FastttCamera instance that captured the photo. + * + * @param videoURL Location of video + */ +- (void)cameraController:(id)cameraController didFinishRecordingVideo:(NSURL *)videoURL; + @end diff --git a/FastttVideoCamera.h b/FastttVideoCamera.h deleted file mode 100644 index dd2fa2f..0000000 --- a/FastttVideoCamera.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// FastttVideoCamera.h -// Pods -// -// Created by Justin Khan on 2015-03-24. -// -// - -#import "FastttCamera.h" - -@interface FastttVideoCamera : FastttCamera - -@end diff --git a/FastttVideoCamera.m b/FastttVideoCamera.m deleted file mode 100644 index 87bbe20..0000000 --- a/FastttVideoCamera.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// FastttVideoCamera.m -// Pods -// -// Created by Justin Khan on 2015-03-24. -// -// - -#import "FastttVideoCamera.h" - -@interface FastttVideoCamera () - -@end - -@implementation FastttVideoCamera - - -@end From ebbfcba6d664ca1f339957045ffc14c49d41b69d Mon Sep 17 00:00:00 2001 From: Justin Khan Date: Tue, 24 Mar 2015 15:38:56 -0400 Subject: [PATCH 06/15] Added correct orientation for the video --- FastttCamera/FastttCamera.m | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index aaec3bd..0cf05cd 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -446,6 +446,29 @@ - (void)_takePhoto { - (void)startRecordingVideo { + 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 ([videoConnection isVideoOrientationSupported]) { + [videoConnection setVideoOrientation:[self _currentCaptureVideoOrientationForDevice]]; + } + + if ([videoConnection isVideoMirroringSupported]) { + [videoConnection setVideoMirrored:(_cameraDevice == FastttCameraDeviceFront)]; + } + NSString *plistPath; NSString *rootPath; rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; From e4e179d9d05787fda96a4dd9a24b0642cac9e1a1 Mon Sep 17 00:00:00 2001 From: Justin Khan Date: Tue, 24 Mar 2015 16:19:31 -0400 Subject: [PATCH 07/15] Added properties if the user wants to disable cropping and fixing the video's orientation --- FastttCamera/FastttCamera.m | 5 ++++- FastttCamera/FastttCameraInterface.h | 21 ++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index 0cf05cd..783e271 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -30,7 +30,8 @@ @implementation FastttCamera @synthesize delegate = _delegate, returnsRotatedPreview = _returnsRotatedPreview, showsFocusView = _showsFocusView, maxScaledDimension = _maxScaledDimension, normalizesImageOrientations = _normalizesImageOrientations, cropsImageToVisibleAspectRatio = _cropsImageToVisibleAspectRatio, interfaceRotatesWithOrientation = _interfaceRotatesWithOrientation, handlesTapFocus = _handlesTapFocus, scalesImage = _scalesImage, - cameraDevice = _cameraDevice, cameraFlashMode = _cameraFlashMode, movieFileOutput = _movieFileOutput; + cameraDevice = _cameraDevice, cameraFlashMode = _cameraFlashMode, movieFileOutput = _movieFileOutput, + normalizesVideoOrientation = _normalizesVideoOrientation, cropsVideoToVisibleAspectRatio = _cropsVideoToVisibleAspectRatio; - (instancetype)init { if ((self = [super init])) { @@ -43,6 +44,8 @@ - (instancetype)init { _scalesImage = YES; _maxScaledDimension = 0.f; _normalizesImageOrientations = YES; + _normalizesVideoOrientation = YES; + _cropsVideoToVisibleAspectRatio = YES; _returnsRotatedPreview = YES; _interfaceRotatesWithOrientation = YES; _cameraDevice = FastttCameraDeviceRear; diff --git a/FastttCamera/FastttCameraInterface.h b/FastttCamera/FastttCameraInterface.h index 7eb6091..47307cf 100644 --- a/FastttCamera/FastttCameraInterface.h +++ b/FastttCamera/FastttCameraInterface.h @@ -81,6 +81,16 @@ */ @property(nonatomic, assign) BOOL interfaceRotatesWithOrientation; +/** + * 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; + #pragma mark - Camera State /** @@ -262,8 +272,17 @@ * * @param cameraController The FastttCamera instance that captured the photo. * - * @param videoURL Location of video + * @param videoURL Location of the video without the proper cropping and orientation */ - (void)cameraController:(id)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)cameraController didFinishNormalizedCapturedVideo:(NSURL *)videoURL; + @end From 04add155119ad511bad84bad6d1856a80495d5db Mon Sep 17 00:00:00 2001 From: Quentin Arnault Date: Mon, 27 Nov 2017 17:44:12 +0100 Subject: [PATCH 08/15] Add input into begin configuration --- FastttCamera/FastttCamera.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index a43a824..87513a7 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -435,6 +435,8 @@ - (void)_setupCaptureSession [device unlockForConfiguration]; } + [_session beginConfiguration]; + #if !TARGET_IPHONE_SIMULATOR AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil]; [_session addInput:deviceInput]; @@ -459,8 +461,6 @@ - (void)_setupCaptureSession [self setCameraFlashMode:_cameraFlashMode]; #endif - [_session beginConfiguration]; - NSDictionary *outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG}; _stillImageOutput = [AVCaptureStillImageOutput new]; From f4f9c0858dd767dc8cd643278972c7ee7a84ef58 Mon Sep 17 00:00:00 2001 From: Quentin Arnault Date: Mon, 27 Nov 2017 17:56:37 +0100 Subject: [PATCH 09/15] [F] add video output clean on teardown --- FastttCamera/FastttCamera.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index 87513a7..9b5ab7d 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -506,6 +506,8 @@ - (void)_teardownCaptureSession [_session removeOutput:_stillImageOutput]; _stillImageOutput = nil; + [_session removeOutput:_movieFileOutput]; + _movieFileOutput = nil; [self _removePreviewLayer]; From 73c65a077714ab481ec2c8a5a56e26c18cc6cd35 Mon Sep 17 00:00:00 2001 From: Quentin Arnault Date: Mon, 27 Nov 2017 17:56:49 +0100 Subject: [PATCH 10/15] [F] video recording without sound --- FastttCamera/FastttCamera.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index 9b5ab7d..a06aace 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -574,6 +574,12 @@ - (void)_takePhoto #pragma mark - Capturing Video - (void)startRecordingVideo { + [_session beginConfiguration]; + for (AVCaptureOutput *captureOutput in _session.outputs) { + [_session removeOutput:captureOutput]; + } + [_session addOutput:_movieFileOutput]; + [_session commitConfiguration]; AVCaptureConnection *videoConnection = nil; From 80ea7aaf4736a2d56abf1c90c3e3e0950904bf2e Mon Sep 17 00:00:00 2001 From: Quentin Arnault Date: Mon, 27 Nov 2017 21:49:36 +0100 Subject: [PATCH 11/15] [F] adapt session configuration to have sound each capture --- FastttCamera/FastttCamera.m | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index a06aace..e3730e4 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -441,10 +441,6 @@ - (void)_setupCaptureSession AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil]; [_session addInput:deviceInput]; - AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; - AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil]; - [_session addInput:audioInput]; - switch (device.position) { case AVCaptureDevicePositionBack: _cameraDevice = FastttCameraDeviceRear; @@ -470,7 +466,7 @@ - (void)_setupCaptureSession _movieFileOutput = [AVCaptureMovieFileOutput new]; [_session addOutput:_movieFileOutput]; - + [_session commitConfiguration]; _deviceOrientation = [IFTTTDeviceOrientation new]; @@ -574,13 +570,27 @@ - (void)_takePhoto #pragma mark - Capturing Video - (void)startRecordingVideo { + [_session beginConfiguration]; - for (AVCaptureOutput *captureOutput in _session.outputs) { - [_session removeOutput:captureOutput]; + 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 remx@oveInput:captureInput]; + } } - [_session addOutput:_movieFileOutput]; + + 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]) { From 96692e05f95c0438c85cabedc45c6c55fd59e826 Mon Sep 17 00:00:00 2001 From: Quentin Arnault Date: Mon, 27 Nov 2017 21:57:41 +0100 Subject: [PATCH 12/15] [F] typo --- FastttCamera/FastttCamera.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index e3730e4..354b854 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -582,7 +582,7 @@ - (void)startRecordingVideo { } if (isAudioInput) { - [_session remx@oveInput:captureInput]; + [_session removeInput:captureInput]; } } From 7e9ecdec893834200293553051beb5c98dba64b0 Mon Sep 17 00:00:00 2001 From: Quentin Arnault Date: Tue, 6 Feb 2018 23:14:25 +0100 Subject: [PATCH 13/15] [I] add customization of capture session preset --- FastttCamera/FastttCamera.m | 6 ++++-- FastttCamera/FastttCameraInterface.h | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index 354b854..ec2c0cd 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -52,7 +52,8 @@ @implementation FastttCamera cameraTorchMode = _cameraTorchMode, movieFileOutput = _movieFileOutput, normalizesVideoOrientation = _normalizesVideoOrientation, - cropsVideoToVisibleAspectRatio = _cropsVideoToVisibleAspectRatio; + cropsVideoToVisibleAspectRatio = _cropsVideoToVisibleAspectRatio, + sessionPreset = _sessionPreset; - (instancetype)init { @@ -77,6 +78,7 @@ - (instancetype)init _cameraDevice = FastttCameraDeviceRear; _cameraFlashMode = FastttCameraFlashModeOff; _cameraTorchMode = FastttCameraTorchModeOff; + _sessionPreset = AVCaptureSessionPresetMedium; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) @@ -417,7 +419,7 @@ - (void)_setupCaptureSession dispatch_async(dispatch_get_main_queue(), ^{ _session = [AVCaptureSession new]; - _session.sessionPreset = AVCaptureSessionPresetMedium; + _session.sessionPreset = _sessionPreset; AVCaptureDevice *device = [AVCaptureDevice cameraDevice:self.cameraDevice]; diff --git a/FastttCamera/FastttCameraInterface.h b/FastttCamera/FastttCameraInterface.h index e2a30d8..759349d 100644 --- a/FastttCamera/FastttCameraInterface.h +++ b/FastttCamera/FastttCameraInterface.h @@ -129,6 +129,12 @@ */ @property(nonatomic, assign) BOOL cropsVideoToVisibleAspectRatio; +/** + * Default to AVCaptureSessionPresetMedium. + */ + +@property (nonatomic, assign) AVCaptureSessionPreset sessionPreset; + #pragma mark - Camera State /** From 1b59f1ea207c9a995569e270dfe1d69f68f5e442 Mon Sep 17 00:00:00 2001 From: Quentin Arnault Date: Sat, 10 Feb 2018 18:55:08 +0100 Subject: [PATCH 14/15] [I] add possibility to force camera orientation on video capturing --- FastttCamera/FastttCamera.m | 8 ++++++-- FastttCamera/FastttCameraInterface.h | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index ec2c0cd..ee1dffa 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -53,7 +53,8 @@ @implementation FastttCamera movieFileOutput = _movieFileOutput, normalizesVideoOrientation = _normalizesVideoOrientation, cropsVideoToVisibleAspectRatio = _cropsVideoToVisibleAspectRatio, - sessionPreset = _sessionPreset; + sessionPreset = _sessionPreset, + forcedDeviceOrientationForVideo = _forcedDeviceOrientationForVideo; - (instancetype)init { @@ -79,6 +80,7 @@ - (instancetype)init _cameraFlashMode = FastttCameraFlashModeOff; _cameraTorchMode = FastttCameraTorchModeOff; _sessionPreset = AVCaptureSessionPresetMedium; + _forcedDeviceOrientationForVideo = nil; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) @@ -608,7 +610,9 @@ - (void)startRecordingVideo { } } - if ([videoConnection isVideoOrientationSupported]) { + if (self.forcedDeviceOrientationForVideo) { + [videoConnection setVideoOrientation: self.forcedDeviceOrientationForVideo]; + } else if ([videoConnection isVideoOrientationSupported]) { [videoConnection setVideoOrientation:[self _currentCaptureVideoOrientationForDevice]]; } diff --git a/FastttCamera/FastttCameraInterface.h b/FastttCamera/FastttCameraInterface.h index 759349d..1d25bb2 100644 --- a/FastttCamera/FastttCameraInterface.h +++ b/FastttCamera/FastttCameraInterface.h @@ -135,6 +135,11 @@ @property (nonatomic, assign) AVCaptureSessionPreset sessionPreset; +/** + * Default to nil. + */ +@property (nonatomic, assign) UIDeviceOrientation forcedDeviceOrientationForVideo; + #pragma mark - Camera State /** From 538d50d4e004c3a77c29c791014c29db1beceae1 Mon Sep 17 00:00:00 2001 From: Quentin Arnault Date: Mon, 9 Apr 2018 21:50:36 +0200 Subject: [PATCH 15/15] [F] prevent disturbing music playing in other apps --- FastttCamera/FastttCamera.m | 1 + 1 file changed, 1 insertion(+) diff --git a/FastttCamera/FastttCamera.m b/FastttCamera/FastttCamera.m index ee1dffa..877ea7f 100644 --- a/FastttCamera/FastttCamera.m +++ b/FastttCamera/FastttCamera.m @@ -421,6 +421,7 @@ - (void)_setupCaptureSession dispatch_async(dispatch_get_main_queue(), ^{ _session = [AVCaptureSession new]; + _session.automaticallyConfiguresApplicationAudioSession = false; _session.sessionPreset = _sessionPreset; AVCaptureDevice *device = [AVCaptureDevice cameraDevice:self.cameraDevice];