From d6634decc47ac9353dcf666677d8d5bd3cb5dd39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Fri, 24 Apr 2015 18:59:46 +0300 Subject: [PATCH 01/14] certificate issue --- LLSimpleCameraExample.xcodeproj/project.pbxproj | 2 ++ LLSimpleCameraExample/Info.plist | 2 ++ 2 files changed, 4 insertions(+) diff --git a/LLSimpleCameraExample.xcodeproj/project.pbxproj b/LLSimpleCameraExample.xcodeproj/project.pbxproj index f37e882..f8e4a3c 100644 --- a/LLSimpleCameraExample.xcodeproj/project.pbxproj +++ b/LLSimpleCameraExample.xcodeproj/project.pbxproj @@ -423,6 +423,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; INFOPLIST_FILE = LLSimpleCameraExample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -434,6 +435,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Distribution"; INFOPLIST_FILE = LLSimpleCameraExample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; diff --git a/LLSimpleCameraExample/Info.plist b/LLSimpleCameraExample/Info.plist index bd6bec0..c478a53 100644 --- a/LLSimpleCameraExample/Info.plist +++ b/LLSimpleCameraExample/Info.plist @@ -31,6 +31,8 @@ UISupportedInterfaceOrientations UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight From 28472a9239b2ebb18233f65a3220ef88c19900c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Sun, 24 May 2015 20:01:10 +0300 Subject: [PATCH 02/14] removed unnecessary images --- LLSimpleCameraExample/camera-flash-off.png | Bin 573 -> 0 bytes LLSimpleCameraExample/camera-flash-off@2x.png | Bin 1152 -> 0 bytes LLSimpleCameraExample/camera-flash-on.png | Bin 684 -> 0 bytes LLSimpleCameraExample/camera-flash-on@2x.png | Bin 1320 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 LLSimpleCameraExample/camera-flash-off.png delete mode 100644 LLSimpleCameraExample/camera-flash-off@2x.png delete mode 100644 LLSimpleCameraExample/camera-flash-on.png delete mode 100644 LLSimpleCameraExample/camera-flash-on@2x.png diff --git a/LLSimpleCameraExample/camera-flash-off.png b/LLSimpleCameraExample/camera-flash-off.png deleted file mode 100644 index b38e938cbe672cfc9bc683402b3396e2f83ed38d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 573 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 eI`1b{ZT~;dN3KVlpCt?c0000 Date: Sun, 24 May 2015 20:08:21 +0300 Subject: [PATCH 03/14] alter bundle id --- LLSimpleCameraExample/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LLSimpleCameraExample/Info.plist b/LLSimpleCameraExample/Info.plist index c478a53..a7127c5 100644 --- a/LLSimpleCameraExample/Info.plist +++ b/LLSimpleCameraExample/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.louvredigital.$(PRODUCT_NAME:rfc1034identifier) + com.omerfarukgul.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName From e4068c247774267fb5ea69aec65d37c564c516c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Sun, 24 May 2015 20:10:04 +0300 Subject: [PATCH 04/14] new icons --- LLSimpleCameraExample/camera-flash.png | Bin 0 -> 573 bytes LLSimpleCameraExample/camera-flash@2x.png | Bin 0 -> 1152 bytes LLSimpleCameraExample/cancel.png | Bin 0 -> 868 bytes LLSimpleCameraExample/cancel@2x.png | Bin 0 -> 1205 bytes LLSimpleCameraExample/cancel@3x.png | Bin 0 -> 1975 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 LLSimpleCameraExample/camera-flash.png create mode 100644 LLSimpleCameraExample/camera-flash@2x.png create mode 100644 LLSimpleCameraExample/cancel.png create mode 100644 LLSimpleCameraExample/cancel@2x.png create mode 100644 LLSimpleCameraExample/cancel@3x.png diff --git a/LLSimpleCameraExample/camera-flash.png b/LLSimpleCameraExample/camera-flash.png new file mode 100644 index 0000000000000000000000000000000000000000..b38e938cbe672cfc9bc683402b3396e2f83ed38d GIT binary patch literal 573 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 literal 0 HcmV?d00001 diff --git a/LLSimpleCameraExample/cancel@3x.png b/LLSimpleCameraExample/cancel@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..7aa3e644c758fc6460051c0308a4a4c00caeef6d GIT binary patch literal 1975 zcma)7dpr|rAKyeFnp^fda?A{GPBzm88$+mcTzAk=m^F9X*f60*jt(*zI?dhDLBw2g zD@+$&t?ZbcdiHy{;z`Xr#L@6eL)AVoRjMg;)&D~cu%ke&N4A;2xb8Arp} z*`f&K5IFuK*@p>OLk_2zLZKp|Z{tgyv;g1# zDv_vP+Y&a25Zxe=rJwx_zL#LxD(|+4Da2{1!l0fS*iMuW zEMHpdq76%`|B))B#!mt(mRx(KCNDY>Rk_USbs;*84=)k!3=b0{KQ>RdhTngczf`Q* zYGp3|kE~E7?hjv0f!S)3Dg)2`eezwi6x=Yky*ViDH}=`!@`t5`CUj0kQiN9#-}}Km zjm#|mLU(s}tOw@85oHF>%oiv&zcaG(Rw878j>>udPF-D{QGXsjxasFO4wJ&KEMHLh zpdQTYx=F<4kIDCSIJv_vj{?e;s+MBk(gY#gzb@>X9_7o3WjSmK?t6RQx-n@Xqg(MS zxPA&*iOBN|WQ3f2FHv*72F(2dRn_SR09ne(c;hGk8rYoL@K(4anfM(*0QFCB^?$NL zlmWTJuCTp|nwArz7QOJ-fAVdf1{`qx9&=NT|nsiiany_DhGXEEY9!Oo^h3Xbj#g8&_H`nYlzfSt=SHx)y^pc zN2csn%Y@B1^IAVH`%0j38OX?R_>*ywb^D>Z+v|9AapkU25oUGD);~*}qj661z4byV ziz10$uhaKKx2?198QmNtMawnocG}Klb-^J`#%_Lo8fIg2HOCUH-+0i8B|dfP zjo10Dh8gmYrW52mHJ)ziLg%XS{?%7;jbI~JnqcYFjm4ESLkQ=vY}t1UG3`?*eWm8X@WgL4N3 zUmLlKVX!t9fz0|vxhK&^UcA?vY`|Sp`n}QCMY19F*&22{BP{;pLg|d+26ac~X47_T zd}cy&=b&y2_jb9e^3{qw&+iu%f+f`;t`t@RQ~K z`*_f9o5`EKZbS6mJ@do%dgdLS(`pMW2s$j>nv!GRv>bfRhH6>)Onf|DC&PcV9q~!4 zH;tVmmC>N-O6eXxFf%P}1Dmn3=iKM1j620E0JFxJ9IUn;a^wf} zphluyf&X|qe$9pbVB$`FUfiXZ-U`~})8d0KBA^?OOB{A#9A@Cm`#|)bk7cvRZF`t8 zAGy7vEA0$@6|_(LwQ5n$s>GV-WIE^rbP8_&%F~~Smfyh-flsBXAxrRuo~la8rOf%@ zMMr^L7c6r^zF_^uC-QS8df+PW>92NK{p2Rw2~0|I*AZUr##ln?oRh@4EFuWKePZkY z&qb)tJ->ddwZf>Yh%bZ*QX zb~Aci$BVg4T5fEB+_J=^r8)#f5whD1^_pB{QwMrVOCX7wDNBUA(To~YTXp%Pj1ouF znAZm;_^PCgd9u_m?k#FjTu$&*|KqXip}m&e0K==Xq~0Kps*>u;wWnad9V5-caflrd zyFz Date: Sun, 24 May 2015 20:11:15 +0300 Subject: [PATCH 05/14] Video VC for showing recorded videos --- LLSimpleCameraExample/VideoViewController.h | 13 +++ LLSimpleCameraExample/VideoViewController.m | 103 ++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 LLSimpleCameraExample/VideoViewController.h create mode 100644 LLSimpleCameraExample/VideoViewController.m diff --git a/LLSimpleCameraExample/VideoViewController.h b/LLSimpleCameraExample/VideoViewController.h new file mode 100644 index 0000000..488ca81 --- /dev/null +++ b/LLSimpleCameraExample/VideoViewController.h @@ -0,0 +1,13 @@ +// +// TestVideoViewController.h +// Memento +// +// Created by Ömer Faruk Gül on 22/05/15. +// Copyright (c) 2015 Ömer Faruk Gül. All rights reserved. +// + +#import + +@interface VideoViewController : UIViewController +- (instancetype)initWithVideoUrl:(NSURL *)url; +@end diff --git a/LLSimpleCameraExample/VideoViewController.m b/LLSimpleCameraExample/VideoViewController.m new file mode 100644 index 0000000..87de52d --- /dev/null +++ b/LLSimpleCameraExample/VideoViewController.m @@ -0,0 +1,103 @@ +// +// TestVideoViewController.m +// Memento +// +// Created by Ömer Faruk Gül on 22/05/15. +// Copyright (c) 2015 Ömer Faruk Gül. All rights reserved. +// + +#import "VideoViewController.h" +@import AVFoundation; + +@interface VideoViewController () +@property (strong, nonatomic) NSURL *videoUrl; +@property (strong, nonatomic) AVPlayer *avPlayer; +@property (strong, nonatomic) AVPlayerLayer *avPlayerLayer; +@property (strong, nonatomic) UIButton *cancelButton; +@end + +@implementation VideoViewController + +- (instancetype)initWithVideoUrl:(NSURL *)url { + self = [super init]; + if(self) { + _videoUrl = url; + } + + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor whiteColor]; + + // the video player + self.avPlayer = [AVPlayer playerWithURL:self.videoUrl]; + self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone; + + self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer]; + //self.avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(playerItemDidReachEnd:) + name:AVPlayerItemDidPlayToEndTimeNotification + object:[self.avPlayer currentItem]]; + + CGRect screenRect = [[UIScreen mainScreen] bounds]; + + self.avPlayerLayer.frame = CGRectMake(0, 0, screenRect.size.width, screenRect.size.height); + [self.view.layer addSublayer:self.avPlayerLayer]; + + // cancel button + [self.view addSubview:self.cancelButton]; + [self.cancelButton addTarget:self action:@selector(cancelButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; + self.cancelButton.frame = CGRectMake(0, 0, 44, 44); +} + +- (void)viewWillAppear:(BOOL)animated{ + [super viewWillAppear:animated]; + + [self.avPlayer play]; +} + +- (void)playerItemDidReachEnd:(NSNotification *)notification { + AVPlayerItem *p = [notification object]; + [p seekToTime:kCMTimeZero]; +} + +- (BOOL)prefersStatusBarHidden { + return YES; +} + +- (UIButton *)cancelButton { + if(!_cancelButton) { + UIImage *cancelImage = [UIImage imageNamed:@"cancel.png"]; + UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; + button.tintColor = [UIColor whiteColor]; + [button setImage:cancelImage forState:UIControlStateNormal]; + button.imageView.clipsToBounds = NO; + button.contentEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10); + button.layer.shadowColor = [UIColor blackColor].CGColor; + button.layer.shadowOffset = CGSizeMake(0.0f, 0.0f); + button.layer.shadowOpacity = 0.4f; + button.layer.shadowRadius = 1.0f; + button.clipsToBounds = NO; + + _cancelButton = button; + } + + return _cancelButton; +} + +- (void)cancelButtonPressed:(UIButton *)button { + NSLog(@"cancel button pressed!"); + [self.navigationController popViewControllerAnimated:YES]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +@end From 3f47be8f66eef2d5e65620f533f352f0e9258851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Sun, 24 May 2015 20:12:16 +0300 Subject: [PATCH 06/14] pbxproj update --- .../project.pbxproj | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/LLSimpleCameraExample.xcodeproj/project.pbxproj b/LLSimpleCameraExample.xcodeproj/project.pbxproj index f8e4a3c..cebce36 100644 --- a/LLSimpleCameraExample.xcodeproj/project.pbxproj +++ b/LLSimpleCameraExample.xcodeproj/project.pbxproj @@ -7,12 +7,14 @@ objects = { /* Begin PBXBuildFile section */ + 170030D11B122F3700585CEB /* VideoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 170030D01B122F3700585CEB /* VideoViewController.m */; }; + 170030D51B1231B400585CEB /* cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = 170030D21B1231B400585CEB /* cancel.png */; }; + 170030D61B1231B400585CEB /* cancel@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 170030D31B1231B400585CEB /* cancel@2x.png */; }; + 170030D71B1231B400585CEB /* cancel@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 170030D41B1231B400585CEB /* cancel@3x.png */; }; + 170030DA1B1232D100585CEB /* camera-flash.png in Resources */ = {isa = PBXBuildFile; fileRef = 170030D81B1232D100585CEB /* camera-flash.png */; }; + 170030DB1B1232D100585CEB /* camera-flash@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 170030D91B1232D100585CEB /* camera-flash@2x.png */; }; 1713621B1A0144100034A6FE /* UIImage+FixOrientation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1713621A1A0144100034A6FE /* UIImage+FixOrientation.m */; }; 17BD92341A1776E20016070B /* ImageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BD92331A1776E20016070B /* ImageViewController.m */; }; - 17BD925C1A17EF780016070B /* camera-flash-off.png in Resources */ = {isa = PBXBuildFile; fileRef = 17BD92561A17EF780016070B /* camera-flash-off.png */; }; - 17BD925D1A17EF780016070B /* camera-flash-off@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 17BD92571A17EF780016070B /* camera-flash-off@2x.png */; }; - 17BD925E1A17EF780016070B /* camera-flash-on.png in Resources */ = {isa = PBXBuildFile; fileRef = 17BD92581A17EF780016070B /* camera-flash-on.png */; }; - 17BD925F1A17EF780016070B /* camera-flash-on@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 17BD92591A17EF780016070B /* camera-flash-on@2x.png */; }; 17BD92641A17F0040016070B /* camera-switch.png in Resources */ = {isa = PBXBuildFile; fileRef = 17BD92621A17F0040016070B /* camera-switch.png */; }; 17BD92651A17F0040016070B /* camera-switch@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 17BD92631A17F0040016070B /* camera-switch@2x.png */; }; 17E4C4851A0122A700E61ACD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 17E4C4841A0122A700E61ACD /* main.m */; }; @@ -38,14 +40,17 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 170030CF1B122F3700585CEB /* VideoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoViewController.h; sourceTree = ""; }; + 170030D01B122F3700585CEB /* VideoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VideoViewController.m; sourceTree = ""; }; + 170030D21B1231B400585CEB /* cancel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cancel.png; sourceTree = ""; }; + 170030D31B1231B400585CEB /* cancel@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cancel@2x.png"; sourceTree = ""; }; + 170030D41B1231B400585CEB /* cancel@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cancel@3x.png"; sourceTree = ""; }; + 170030D81B1232D100585CEB /* camera-flash.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camera-flash.png"; sourceTree = ""; }; + 170030D91B1232D100585CEB /* camera-flash@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camera-flash@2x.png"; sourceTree = ""; }; 171362191A0144100034A6FE /* UIImage+FixOrientation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+FixOrientation.h"; sourceTree = ""; }; 1713621A1A0144100034A6FE /* UIImage+FixOrientation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+FixOrientation.m"; sourceTree = ""; }; 17BD92321A1776E20016070B /* ImageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageViewController.h; sourceTree = ""; }; 17BD92331A1776E20016070B /* ImageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageViewController.m; sourceTree = ""; }; - 17BD92561A17EF780016070B /* camera-flash-off.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camera-flash-off.png"; sourceTree = ""; }; - 17BD92571A17EF780016070B /* camera-flash-off@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camera-flash-off@2x.png"; sourceTree = ""; }; - 17BD92581A17EF780016070B /* camera-flash-on.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camera-flash-on.png"; sourceTree = ""; }; - 17BD92591A17EF780016070B /* camera-flash-on@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camera-flash-on@2x.png"; sourceTree = ""; }; 17BD92621A17F0040016070B /* camera-switch.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camera-switch.png"; sourceTree = ""; }; 17BD92631A17F0040016070B /* camera-switch@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camera-switch@2x.png"; sourceTree = ""; }; 17E4C47F1A0122A700E61ACD /* LLSimpleCameraExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LLSimpleCameraExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -93,10 +98,11 @@ children = ( 17BD92621A17F0040016070B /* camera-switch.png */, 17BD92631A17F0040016070B /* camera-switch@2x.png */, - 17BD92561A17EF780016070B /* camera-flash-off.png */, - 17BD92571A17EF780016070B /* camera-flash-off@2x.png */, - 17BD92581A17EF780016070B /* camera-flash-on.png */, - 17BD92591A17EF780016070B /* camera-flash-on@2x.png */, + 170030D81B1232D100585CEB /* camera-flash.png */, + 170030D91B1232D100585CEB /* camera-flash@2x.png */, + 170030D21B1231B400585CEB /* cancel.png */, + 170030D31B1231B400585CEB /* cancel@2x.png */, + 170030D41B1231B400585CEB /* cancel@3x.png */, ); name = Images; sourceTree = ""; @@ -188,6 +194,8 @@ 17E4C4B61A0123E400E61ACD /* Controllers */ = { isa = PBXGroup; children = ( + 170030CF1B122F3700585CEB /* VideoViewController.h */, + 170030D01B122F3700585CEB /* VideoViewController.m */, 17E4C4B71A01285800E61ACD /* HomeViewController.h */, 17E4C4B81A01285800E61ACD /* HomeViewController.m */, 17BD92321A1776E20016070B /* ImageViewController.h */, @@ -276,14 +284,15 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 170030D61B1231B400585CEB /* cancel@2x.png in Resources */, 17BD92641A17F0040016070B /* camera-switch.png in Resources */, 17BD92651A17F0040016070B /* camera-switch@2x.png in Resources */, - 17BD925E1A17EF780016070B /* camera-flash-on.png in Resources */, - 17BD925F1A17EF780016070B /* camera-flash-on@2x.png in Resources */, - 17BD925D1A17EF780016070B /* camera-flash-off@2x.png in Resources */, + 170030DB1B1232D100585CEB /* camera-flash@2x.png in Resources */, 17E4C4931A0122A700E61ACD /* LaunchScreen.xib in Resources */, + 170030D51B1231B400585CEB /* cancel.png in Resources */, 17E4C4901A0122A700E61ACD /* Images.xcassets in Resources */, - 17BD925C1A17EF780016070B /* camera-flash-off.png in Resources */, + 170030D71B1231B400585CEB /* cancel@3x.png in Resources */, + 170030DA1B1232D100585CEB /* camera-flash.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -301,6 +310,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 170030D11B122F3700585CEB /* VideoViewController.m in Sources */, 17BD92341A1776E20016070B /* ImageViewController.m in Sources */, 17E4C4AB1A01235200E61ACD /* LLSimpleCamera.m in Sources */, 17E4C4B31A0123C100E61ACD /* UIImage+Crop.m in Sources */, From f20ea3869bcc35120f296ebd814ed776bc11e459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Sun, 24 May 2015 20:13:02 +0300 Subject: [PATCH 07/14] video methods added and class refactored --- LLSimpleCamera/LLSimpleCamera.h | 51 ++++-- LLSimpleCamera/LLSimpleCamera.m | 316 ++++++++++++++++++++++---------- 2 files changed, 254 insertions(+), 113 deletions(-) diff --git a/LLSimpleCamera/LLSimpleCamera.h b/LLSimpleCamera/LLSimpleCamera.h index 18052b9..0e82a0d 100644 --- a/LLSimpleCamera/LLSimpleCamera.h +++ b/LLSimpleCamera/LLSimpleCamera.h @@ -21,17 +21,11 @@ typedef enum : NSUInteger { CameraFlashAuto } CameraFlash; -typedef enum : NSUInteger { - CameraQualityLow, - CameraQualityMedium, - CameraQualityHigh, - CameraQualityPhoto -} CameraQuality; - extern NSString *const LLSimpleCameraErrorDomain; typedef enum : NSUInteger { - LLSimpleCameraErrorCodePermission = 10, - LLSimpleCameraErrorCodeSession = 11 + LLSimpleCameraErrorCodeCameraPermission = 10, + LLSimpleCameraErrorCodeMicrophonePermission = 11, + LLSimpleCameraErrorCodeSession = 12 } LLSimpleCameraErrorCode; @interface LLSimpleCamera : UIViewController @@ -56,6 +50,16 @@ typedef enum : NSUInteger { */ @property (nonatomic) CameraPosition position; +/** + * Boolean value to indicate if the video is enabled. + */ +@property (nonatomic, getter=isVideoEnabled) BOOL videoEnabled; + +/** + * Boolean value to indicate if the camera is recording a video at the current moment. + */ +@property (nonatomic, getter=isRecording) BOOL recording; + /** * Fixess the orientation after the image is captured is set to Yes. * see: http://stackoverflow.com/questions/5427656/ios-uiimagepickercontroller-result-image-orientation-after-upload @@ -73,11 +77,27 @@ typedef enum : NSUInteger { */ @property (nonatomic) BOOL useDeviceOrientation; +/** + * Use this method to request camera permission before initalizing LLSimpleCamera. + */ ++ (void)requestCameraPermission:(void (^)(BOOL granted))completionBlock; + +/** + * Use this method to request microphone permission before initalizing LLSimpleCamera. + */ ++ (void)requestMicrophonePermission:(void (^)(BOOL granted))completionBlock; + /** * Returns an instance of LLSimpleCamera with the given quality. - * @param quality The quality of the camera. + * Quality parameter could be any variable starting with AVCaptureSessionPreset. + */ +- (instancetype)initWithQuality:(NSString *)quality position:(CameraPosition)position videoEnabled:(BOOL)videoEnabled; + +/** + * Returns an instance of LLSimpleCamera with quality "AVCaptureSessionPresetHigh" and position "CameraPositionBack". + * @param videEnabled: Set to YES to enable video recording. */ -- (instancetype)initWithQuality:(CameraQuality)quality andPosition:(CameraPosition)position; +- (instancetype)initWithVideoEnabled:(BOOL)videoEnabled; /** * Starts running the camera session. @@ -89,6 +109,9 @@ typedef enum : NSUInteger { */ - (void)stop; +- (void)startRecordingWithOutputUrl:(NSURL *)url; +- (void)stopRecording:(void (^)(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error))didRecord; + /** * Attaches the LLSimpleCamera to another view controller with a frame. It basically adds the LLSimpleCamera as a * child vc to the given vc. @@ -112,6 +135,11 @@ typedef enum : NSUInteger { */ - (BOOL)isFlashAvailable; +/** + * Checks if torch (flash for video) is avilable for the currently active device. + */ +- (BOOL)isTorchAvailable; + /** * Alter the layer and the animation displayed when the user taps on screen. * @param layer Layer to be displayed @@ -119,7 +147,6 @@ typedef enum : NSUInteger { */ - (void)alterFocusBox:(CALayer *)layer animation:(CAAnimation *)animation; - /** * Capture the image. * @param onCapture a block triggered after the capturing the photo. diff --git a/LLSimpleCamera/LLSimpleCamera.m b/LLSimpleCamera/LLSimpleCamera.m index bd29de7..ea353ce 100644 --- a/LLSimpleCamera/LLSimpleCamera.m +++ b/LLSimpleCamera/LLSimpleCamera.m @@ -10,31 +10,54 @@ #import #import "UIImage+FixOrientation.h" -@interface LLSimpleCamera () -@property (nonatomic) CameraQuality cameraQuality; +@interface LLSimpleCamera () +@property (copy, nonatomic) NSString *cameraQuality; @property (strong, nonatomic) UIView *preview; @property (strong, nonatomic) AVCaptureStillImageOutput *stillImageOutput; @property (strong, nonatomic) AVCaptureSession *session; -@property (strong, nonatomic) AVCaptureDevice *captureDevice; -@property (strong, nonatomic) AVCaptureDeviceInput *deviceInput; +@property (strong, nonatomic) AVCaptureDevice *videoCaptureDevice; +@property (strong, nonatomic) AVCaptureDevice *audioCaptureDevice; +@property (strong, nonatomic) AVCaptureDeviceInput *videoDeviceInput; +@property (strong, nonatomic) AVCaptureDeviceInput *audioDeviceInput; @property (strong, nonatomic) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer; @property (strong, nonatomic) UITapGestureRecognizer *tapGesture; @property (strong, nonatomic) CALayer *focusBoxLayer; @property (strong, nonatomic) CAAnimation *focusBoxAnimation; +@property (strong, nonatomic) AVCaptureMovieFileOutput *movieFileOutput; +@property (nonatomic, copy) void (^didRecord)(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error); @end NSString *const LLSimpleCameraErrorDomain = @"LLSimpleCameraErrorDomain"; @implementation LLSimpleCamera -- (instancetype)initWithQuality:(CameraQuality)quality andPosition:(CameraPosition)position { +- (instancetype)init { + self = [self initWithVideoEnabled:NO]; + if(self) { + } + + return self; +} + +- (instancetype)initWithVideoEnabled:(BOOL)videoEnabled { + self = [self initWithQuality:AVCaptureSessionPresetHigh position:CameraPositionBack videoEnabled:NO]; + if(self) { + } + + return self; +} + +- (instancetype)initWithQuality:(NSString *)quality position:(CameraPosition)position videoEnabled:(BOOL)videoEnabled { self = [super initWithNibName:nil bundle:nil]; if(self) { - self.cameraQuality = quality; - self.cameraPosition = position; - self.fixOrientationAfterCapture = NO; - self.tapToFocus = YES; - self.useDeviceOrientation = NO; + _cameraQuality = quality; + _position = position; + _fixOrientationAfterCapture = NO; + _tapToFocus = YES; + _useDeviceOrientation = NO; + _flash = CameraFlashOff; + _videoEnabled = videoEnabled; + _recording = NO; } return self; @@ -43,8 +66,6 @@ - (instancetype)initWithQuality:(CameraQuality)quality andPosition:(CameraPositi - (void)viewDidLoad { [super viewDidLoad]; - _flash = CameraFlashOff; - self.view.backgroundColor = [UIColor clearColor]; self.view.autoresizingMask = UIViewAutoresizingNone; @@ -116,63 +137,51 @@ - (void) previewTapped: (UIGestureRecognizer *) gestureRecognizer #pragma mark Camera Actions - (void)start { - // in iOS7 & iOS8 we have check if we have permission t camera - if ([AVCaptureDevice respondsToSelector:@selector(requestAccessForMediaType: completionHandler:)]) { - [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { - if (granted) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self initialize]; - }); - } else { - NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain - code:LLSimpleCameraErrorCodePermission + [LLSimpleCamera requestCameraPermission:^(BOOL granted) { + if(granted) { + // request microphone permission if video is enabled + if(self.videoEnabled) { + [LLSimpleCamera requestMicrophonePermission:^(BOOL granted) { + if(granted) { + [self initialize]; + } + else { + NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain + code:LLSimpleCameraErrorCodeMicrophonePermission + userInfo:nil]; + if(self.onError) { + self.onError(self, error); + } + } + }]; + } + else { + [self initialize]; + } + } + else { + NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain + code:LLSimpleCameraErrorCodeCameraPermission userInfo:nil]; - - if(self.onError) { - dispatch_async(dispatch_get_main_queue(), ^{ - self.onError(self, error); - }); - } + if(self.onError) { + self.onError(self, error); } - }]; - } else { - [self initialize]; - } + } + }]; } - (void)initialize { if(!_session) { - self.session = [[AVCaptureSession alloc] init]; + _session = [[AVCaptureSession alloc] init]; + _session.sessionPreset = self.cameraQuality; - NSString *sessionPreset = nil; - - switch (self.cameraQuality) { - case CameraQualityHigh: - sessionPreset = AVCaptureSessionPresetHigh; - break; - case CameraQualityMedium: - sessionPreset = AVCaptureSessionPresetMedium; - break; - case CameraQualityLow: - sessionPreset = AVCaptureSessionPresetLow; - break; - default: - sessionPreset = AVCaptureSessionPresetPhoto; - break; - } - - self.session.sessionPreset = sessionPreset; - - AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session]; - - // set size + // preview layer CGRect bounds = self.preview.layer.bounds; - captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; - captureVideoPreviewLayer.bounds = bounds; - captureVideoPreviewLayer.position = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); - [self.preview.layer addSublayer:captureVideoPreviewLayer]; - - self.captureVideoPreviewLayer = captureVideoPreviewLayer; + _captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session]; + _captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; + _captureVideoPreviewLayer.bounds = bounds; + _captureVideoPreviewLayer.position = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); + [self.preview.layer addSublayer:_captureVideoPreviewLayer]; AVCaptureDevicePosition devicePosition; switch (self.position) { @@ -188,22 +197,46 @@ - (void)initialize { } if(devicePosition == AVCaptureDevicePositionUnspecified) { - self.captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + _videoCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; } else { - self.captureDevice = [self cameraWithPosition:devicePosition]; + _videoCaptureDevice = [self cameraWithPosition:devicePosition]; } NSError *error = nil; - _deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:self.captureDevice error:&error]; + _videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_videoCaptureDevice error:&error]; - if (!_deviceInput) { + if (!_videoDeviceInput) { if(self.onError) { self.onError(self, error); } return; } - [self.session addInput:_deviceInput]; + + if([self.session canAddInput:_videoDeviceInput]) { + [self.session addInput:_videoDeviceInput]; + } + + // audio + if(self.videoEnabled) { + _audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; + _audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_audioCaptureDevice error:&error]; + if (!_audioDeviceInput) { + if(self.onError) { + self.onError(self, error); + } + } + + if([self.session canAddInput:_audioDeviceInput]) { + [self.session addInput:_audioDeviceInput]; + } + + _movieFileOutput = [[AVCaptureMovieFileOutput alloc] init]; + if([self.session canAddOutput:_movieFileOutput]) { + [self.session addOutput:_movieFileOutput]; + } + } + self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init]; NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVideoCodecJPEG, AVVideoCodecKey, nil]; @@ -224,6 +257,8 @@ - (void)stop { } +#pragma mark Image Methods + -(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture exactSeenImage:(BOOL)exactSeenImage { if(!self.session) { @@ -238,10 +273,10 @@ -(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *m AVCaptureConnection *videoConnection = [self captureConnection]; videoConnection.videoOrientation = [self orientationForConnection]; + // freeze the screen + [self.captureVideoPreviewLayer.connection setEnabled:NO]; + [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) { - - //Stop capturing data to freeze the screen to indicate the pictrue has been taken - [self.captureVideoPreviewLayer.connection setEnabled:NO]; UIImage *image = nil; NSDictionary *metadata = nil; @@ -276,13 +311,61 @@ -(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *m [self capture:onCapture exactSeenImage:NO]; } +#pragma mark Video Methods + +- (void)startRecordingWithOutputUrl:(NSURL *)url { + if(self.flash == CameraFlashOn) { + [self enableTorch:YES]; + } + [self.movieFileOutput startRecordingToOutputFileURL:url recordingDelegate:self]; +} + +- (void)stopRecording:(void (^)(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error))completionBlock { + self.didRecord = completionBlock; + [self.movieFileOutput stopRecording]; +} + +- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections { + self.recording = YES; +} + +- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error { + + self.recording = NO; + [self enableTorch:NO]; + + if(self.didRecord) { + self.didRecord(self, outputFileURL, error); + } +} + +- (void)enableTorch:(BOOL)enabled { + // check if the device has a toch, otherwise don't even bother to take any action. + if([self isTorchAvailable]) { + [self.session beginConfiguration]; + [self.videoCaptureDevice lockForConfiguration:nil]; + if (enabled) { + [self.videoCaptureDevice setTorchMode:AVCaptureTorchModeOn]; + } else { + [self.videoCaptureDevice setTorchMode:AVCaptureTorchModeOff]; + } + [self.videoCaptureDevice unlockForConfiguration]; + [self.session commitConfiguration]; + } +} + +#pragma mark Helper Methods - (UIImage *)cropImageUsingPreviewBounds:(UIImage *)image { - CGRect outputRect = [self.captureVideoPreviewLayer metadataOutputRectOfInterestForRect:self.captureVideoPreviewLayer.bounds]; + + CGRect previewBounds = self.captureVideoPreviewLayer.bounds; + CGRect outputRect = [self.captureVideoPreviewLayer metadataOutputRectOfInterestForRect:previewBounds]; + CGImageRef takenCGImage = image.CGImage; size_t width = CGImageGetWidth(takenCGImage); size_t height = CGImageGetHeight(takenCGImage); - CGRect cropRect = CGRectMake(outputRect.origin.x * width, outputRect.origin.y * height, outputRect.size.width * width, outputRect.size.height * height); + CGRect cropRect = CGRectMake(outputRect.origin.x * width, outputRect.origin.y * height, + outputRect.size.width * width, outputRect.size.height * height); CGImageRef cropCGImage = CGImageCreateWithImageInRect(takenCGImage, cropRect); image = [UIImage imageWithCGImage:cropCGImage scale:1 orientation:image.imageOrientation]; @@ -291,15 +374,11 @@ - (UIImage *)cropImageUsingPreviewBounds:(UIImage *)image { return image; } -#pragma mark Helper Methods - - (AVCaptureConnection *)captureConnection { AVCaptureConnection *videoConnection = nil; - for (AVCaptureConnection *connection in self.stillImageOutput.connections) - { - for (AVCaptureInputPort *port in [connection inputPorts]) - { + for (AVCaptureConnection *connection in self.stillImageOutput.connections) { + for (AVCaptureInputPort *port in [connection inputPorts]) { if ([[port mediaType] isEqual:AVMediaTypeVideo]) { videoConnection = connection; break; @@ -313,16 +392,16 @@ - (AVCaptureConnection *)captureConnection { return videoConnection; } -- (void)setCaptureDevice:(AVCaptureDevice *)captureDevice { - _captureDevice = captureDevice; +- (void)setVideoCaptureDevice:(AVCaptureDevice *)videoCaptureDevice { + _videoCaptureDevice = videoCaptureDevice; - if(captureDevice.flashMode == AVCaptureFlashModeAuto) { + if(videoCaptureDevice.flashMode == AVCaptureFlashModeAuto) { _flash = CameraFlashAuto; } - else if(captureDevice.flashMode == AVCaptureFlashModeOn) { + else if(videoCaptureDevice.flashMode == AVCaptureFlashModeOn) { _flash = CameraFlashOn; } - else if(captureDevice.flashMode == AVCaptureFlashModeOff) { + else if(videoCaptureDevice.flashMode == AVCaptureFlashModeOff) { _flash = CameraFlashOff; } else { @@ -331,12 +410,16 @@ - (void)setCaptureDevice:(AVCaptureDevice *)captureDevice { // trigger block if(self.onDeviceChange) { - self.onDeviceChange(self, captureDevice); + self.onDeviceChange(self, videoCaptureDevice); } } - (BOOL)isFlashAvailable { - return self.captureDevice.isFlashAvailable; + return self.videoCaptureDevice.hasFlash && self.videoCaptureDevice.isFlashAvailable; +} + +- (BOOL)isTorchAvailable { + return self.videoCaptureDevice.hasTorch && self.videoCaptureDevice.isTorchAvailable; } - (BOOL)updateFlashMode:(CameraFlash)cameraFlash { @@ -356,11 +439,11 @@ - (BOOL)updateFlashMode:(CameraFlash)cameraFlash { } - if([_captureDevice isFlashModeSupported:flashMode]) { + if([self.videoCaptureDevice isFlashModeSupported:flashMode]) { NSError *error; - if([_captureDevice lockForConfiguration:&error]) { - _captureDevice.flashMode = flashMode; - [_captureDevice unlockForConfiguration]; + if([self.videoCaptureDevice lockForConfiguration:&error]) { + self.videoCaptureDevice.flashMode = flashMode; + [self.videoCaptureDevice unlockForConfiguration]; _flash = cameraFlash; return YES; @@ -398,29 +481,27 @@ - (void)setCameraPosition:(CameraPosition)cameraPosition return; } - // indicate that some changes will be made to the session [self.session beginConfiguration]; // remove existing input - AVCaptureInput* currentCameraInput = [self.session.inputs objectAtIndex:0]; - [self.session removeInput:currentCameraInput]; + [self.session removeInput:self.videoDeviceInput]; // get new input - AVCaptureDevice *newCamera = nil; - if(((AVCaptureDeviceInput*)currentCameraInput).device.position == AVCaptureDevicePositionBack) { - newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront]; + AVCaptureDevice *device = nil; + if(self.videoDeviceInput.device.position == AVCaptureDevicePositionBack) { + device = [self cameraWithPosition:AVCaptureDevicePositionFront]; } else { - newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack]; + device = [self cameraWithPosition:AVCaptureDevicePositionBack]; } - if(!newCamera) { + if(!device) { return; } // add input to session NSError *error = nil; - AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:newCamera error:&error]; + AVCaptureDeviceInput *videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error]; if(error) { if(self.onError) { self.onError(self, error); @@ -431,10 +512,11 @@ - (void)setCameraPosition:(CameraPosition)cameraPosition _position = cameraPosition; - [self.session addInput:newVideoInput]; + [self.session addInput:videoInput]; [self.session commitConfiguration]; - self.captureDevice = newCamera; + self.videoCaptureDevice = device; + self.videoDeviceInput = videoInput; } @@ -454,7 +536,7 @@ - (void) focusAtPoint:(CGPoint)point { //NSLog(@"Focusing at point %@", NSStringFromCGPoint(point)); - AVCaptureDevice *device = _deviceInput.device; + AVCaptureDevice *device = self.videoCaptureDevice; if (device.isFocusPointOfInterestSupported && [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) { NSError *error; if ([device lockForConfiguration:&error]) { @@ -499,7 +581,7 @@ - (CGPoint)convertToPointOfInterestFromViewCoordinates:(CGPoint)viewCoordinates pointOfInterest = CGPointMake(viewCoordinates.y / frameSize.height, 1.f - (viewCoordinates.x / frameSize.width)); } else { CGRect cleanAperture; - for (AVCaptureInputPort *port in [self.session.inputs.lastObject ports]) { + for (AVCaptureInputPort *port in [self.videoDeviceInput ports]) { if (port.mediaType == AVMediaTypeVideo) { cleanAperture = CMVideoFormatDescriptionGetCleanAperture([port formatDescription], YES); CGSize apertureSize = cleanAperture.size; @@ -622,4 +704,36 @@ - (void)didReceiveMemoryWarning { // Dispose of any resources that can be recreated. } + +#pragma mark static methods + ++ (void)requestCameraPermission:(void (^)(BOOL granted))completionBlock { + if ([AVCaptureDevice respondsToSelector:@selector(requestAccessForMediaType: completionHandler:)]) { + [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { + // return to main thread + dispatch_async(dispatch_get_main_queue(), ^{ + if(completionBlock) { + completionBlock(granted); + } + }); + }]; + } else { + completionBlock(YES); + } + +} + ++ (void)requestMicrophonePermission:(void (^)(BOOL granted))completionBlock { + if([[AVAudioSession sharedInstance] respondsToSelector:@selector(requestRecordPermission:)]) { + [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) { + // return to main thread + dispatch_async(dispatch_get_main_queue(), ^{ + if(completionBlock) { + completionBlock(granted); + } + }); + }]; + } +} + @end \ No newline at end of file From 9fadbe378aab43c106a330c40bf58c872d0cec4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Sun, 24 May 2015 20:13:55 +0300 Subject: [PATCH 08/14] Image vc updated --- LLSimpleCameraExample/ImageViewController.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/LLSimpleCameraExample/ImageViewController.m b/LLSimpleCameraExample/ImageViewController.m index 1d3df0c..3764337 100644 --- a/LLSimpleCameraExample/ImageViewController.m +++ b/LLSimpleCameraExample/ImageViewController.m @@ -15,7 +15,6 @@ @interface ImageViewController () @property (strong, nonatomic) UIImageView *imageView; @property (strong, nonatomic) UILabel *infoLabel; @property (strong, nonatomic) UIButton *cancelButton; - @end @implementation ImageViewController @@ -23,7 +22,7 @@ @implementation ImageViewController - (instancetype)initWithImage:(UIImage *)image { self = [super initWithNibName:nil bundle:nil]; if(self) { - self.image = image; + _image = image; } return self; @@ -42,7 +41,7 @@ - (void)viewDidLoad { self.imageView.image = self.image; [self.view addSubview:self.imageView]; - NSString *info = [NSString stringWithFormat:@"Size: %@ - Orientation: %d", NSStringFromCGSize(self.image.size), self.image.imageOrientation]; + NSString *info = [NSString stringWithFormat:@"Size: %@ - Orientation: %ld", NSStringFromCGSize(self.image.size), (long)self.image.imageOrientation]; self.infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 20)]; self.infoLabel.backgroundColor = [[UIColor darkGrayColor] colorWithAlphaComponent:0.7]; From 93c4ca60bd383de6cc0d2c646f4f808b56186026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Sun, 24 May 2015 20:14:36 +0300 Subject: [PATCH 09/14] Exampe updated for video recording --- LLSimpleCameraExample/HomeViewController.m | 96 +++++++++++++++++----- 1 file changed, 77 insertions(+), 19 deletions(-) diff --git a/LLSimpleCameraExample/HomeViewController.m b/LLSimpleCameraExample/HomeViewController.m index b3fc8b9..e5b534d 100644 --- a/LLSimpleCameraExample/HomeViewController.m +++ b/LLSimpleCameraExample/HomeViewController.m @@ -9,6 +9,7 @@ #import "HomeViewController.h" #import "ViewUtils.h" #import "ImageViewController.h" +#import "VideoViewController.h" @interface HomeViewController () @property (strong, nonatomic) LLSimpleCamera *camera; @@ -16,6 +17,7 @@ @interface HomeViewController () @property (strong, nonatomic) UIButton *snapButton; @property (strong, nonatomic) UIButton *switchButton; @property (strong, nonatomic) UIButton *flashButton; +@property (strong, nonatomic) UISegmentedControl *segmentedControl; @end @implementation HomeViewController @@ -31,7 +33,9 @@ - (void)viewDidLoad { // ----- initialize camera -------- // // create camera vc - self.camera = [[LLSimpleCamera alloc] initWithQuality:CameraQualityPhoto andPosition:CameraPositionBack]; + self.camera = [[LLSimpleCamera alloc] initWithQuality:AVCaptureSessionPresetHigh + position:CameraPositionBack + videoEnabled:YES]; // attach to a view controller [self.camera attachToViewController:self withFrame:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)]; @@ -66,9 +70,12 @@ - (void)viewDidLoad { NSLog(@"Camera error: %@", error); if([error.domain isEqualToString:LLSimpleCameraErrorDomain]) { - if(error.code == LLSimpleCameraErrorCodePermission) { - if(weakSelf.errorLabel) + if(error.code == LLSimpleCameraErrorCodeCameraPermission || + error.code == LLSimpleCameraErrorCodeMicrophonePermission) { + + if(weakSelf.errorLabel) { [weakSelf.errorLabel removeFromSuperview]; + } UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero]; label.text = @"We need permission for the camera.\nPlease go to your settings."; @@ -89,7 +96,7 @@ - (void)viewDidLoad { // ----- camera buttons -------- // // snap button to capture image - self.snapButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + self.snapButton = [UIButton buttonWithType:UIButtonTypeCustom]; self.snapButton.frame = CGRectMake(0, 0, 70.0f, 70.0f); self.snapButton.clipsToBounds = YES; self.snapButton.layer.cornerRadius = self.snapButton.width / 2.0f; @@ -102,21 +109,34 @@ - (void)viewDidLoad { [self.view addSubview:self.snapButton]; // button to toggle flash - self.flashButton = [UIButton buttonWithType:UIButtonTypeCustom]; + self.flashButton = [UIButton buttonWithType:UIButtonTypeSystem]; self.flashButton.frame = CGRectMake(0, 0, 16.0f + 20.0f, 24.0f + 20.0f); - [self.flashButton setImage:[UIImage imageNamed:@"camera-flash-off.png"] forState:UIControlStateNormal]; - [self.flashButton setImage:[UIImage imageNamed:@"camera-flash-on.png"] forState:UIControlStateSelected]; + self.flashButton.tintColor = [UIColor whiteColor]; + [self.flashButton setImage:[UIImage imageNamed:@"camera-flash.png"] forState:UIControlStateNormal]; self.flashButton.imageEdgeInsets = UIEdgeInsetsMake(10.0f, 10.0f, 10.0f, 10.0f); [self.flashButton addTarget:self action:@selector(flashButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:self.flashButton]; // button to toggle camera positions - self.switchButton = [UIButton buttonWithType:UIButtonTypeCustom]; + self.switchButton = [UIButton buttonWithType:UIButtonTypeSystem]; self.switchButton.frame = CGRectMake(0, 0, 29.0f + 20.0f, 22.0f + 20.0f); + self.switchButton.tintColor = [UIColor whiteColor]; [self.switchButton setImage:[UIImage imageNamed:@"camera-switch.png"] forState:UIControlStateNormal]; self.switchButton.imageEdgeInsets = UIEdgeInsetsMake(10.0f, 10.0f, 10.0f, 10.0f); [self.switchButton addTarget:self action:@selector(switchButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:self.switchButton]; + + + self.segmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"Picture",@"Video"]]; + self.segmentedControl.frame = CGRectMake(12.0f, screenRect.size.height - 67.0f, 120.0f, 32.0f); + self.segmentedControl.selectedSegmentIndex = 0; + self.segmentedControl.tintColor = [UIColor whiteColor]; + [self.segmentedControl addTarget:self action:@selector(segmentedControlValueChanged:) forControlEvents:UIControlEventValueChanged]; + [self.view addSubview:self.segmentedControl]; +} + +- (void)segmentedControlValueChanged:(UISegmentedControl *)control { + NSLog(@"Segment value changed!"); } - (void)viewWillAppear:(BOOL)animated { @@ -139,40 +159,78 @@ - (void)switchButtonPressed:(UIButton *)button { [self.camera togglePosition]; } +- (NSURL *)applicationDocumentsDirectory { + return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory + inDomains:NSUserDomainMask] lastObject]; +} + - (void)flashButtonPressed:(UIButton *)button { if(self.camera.flash == CameraFlashOff) { BOOL done = [self.camera updateFlashMode:CameraFlashOn]; if(done) { self.flashButton.selected = YES; + self.flashButton.tintColor = [UIColor yellowColor]; } } else { BOOL done = [self.camera updateFlashMode:CameraFlashOff]; if(done) { self.flashButton.selected = NO; + self.flashButton.tintColor = [UIColor whiteColor]; } } } - (void)snapButtonPressed:(UIButton *)button { - // capture - [self.camera capture:^(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error) { - if(!error) { + if(self.segmentedControl.selectedSegmentIndex == 0) { + // capture + [self.camera capture:^(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error) { + if(!error) { + + // we should stop the camera, since we don't need it anymore. We will open a new vc. + // this very important, otherwise you may experience memory crashes + [camera stop]; + + // show the image + ImageViewController *imageVC = [[ImageViewController alloc] initWithImage:image]; + [self presentViewController:imageVC animated:NO completion:nil]; + } + else { + NSLog(@"An error has occured: %@", error); + } + } exactSeenImage:YES]; + } + else { + + if(!self.camera.isRecording) { + self.segmentedControl.hidden = YES; + self.flashButton.hidden = YES; + self.switchButton.hidden = YES; - // we should stop the camera, since we don't need it anymore. We will open a new vc. - // this very important, otherwise you may experience memory crashes - [camera stop]; + self.snapButton.layer.borderColor = [UIColor redColor].CGColor; + self.snapButton.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.5]; - // show the image - ImageViewController *imageVC = [[ImageViewController alloc] initWithImage:image]; - [self presentViewController:imageVC animated:NO completion:nil]; + // start recording + NSURL *outputURL = [[[self applicationDocumentsDirectory] + URLByAppendingPathComponent:@"test1"] URLByAppendingPathExtension:@"mov"]; + [self.camera startRecordingWithOutputUrl:outputURL]; } else { - NSLog(@"An error has occured: %@", error); + self.segmentedControl.hidden = NO; + self.flashButton.hidden = NO; + self.switchButton.hidden = NO; + + self.snapButton.layer.borderColor = [UIColor whiteColor].CGColor; + self.snapButton.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5]; + + [self.camera stopRecording:^(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error) { + VideoViewController *vc = [[VideoViewController alloc] initWithVideoUrl:outputFileUrl]; + [self.navigationController pushViewController:vc animated:YES]; + }]; } - } exactSeenImage:YES]; + } } /* other lifecycle methods */ From 5435c459bf5406fbf7edfa2a9b67d459862b6338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Sun, 24 May 2015 20:56:41 +0300 Subject: [PATCH 10/14] description update --- LLSimpleCameraExample/UIImage+Crop.h | 4 ++-- LLSimpleCameraExample/UIImage+Crop.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/LLSimpleCameraExample/UIImage+Crop.h b/LLSimpleCameraExample/UIImage+Crop.h index 19f5215..803a2af 100644 --- a/LLSimpleCameraExample/UIImage+Crop.h +++ b/LLSimpleCameraExample/UIImage+Crop.h @@ -1,9 +1,9 @@ // // UIImage+Crop.h -// Frizzbee +// LLSimpleCamera // // Created by Ömer Faruk Gül on 27/10/14. -// Copyright (c) 2014 Louvre Digital. All rights reserved. +// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved. // #import diff --git a/LLSimpleCameraExample/UIImage+Crop.m b/LLSimpleCameraExample/UIImage+Crop.m index 600079d..aac9484 100644 --- a/LLSimpleCameraExample/UIImage+Crop.m +++ b/LLSimpleCameraExample/UIImage+Crop.m @@ -1,9 +1,9 @@ // // UIImage+Crop.m -// Frizzbee +// LLSimpleCamera // // Created by Ömer Faruk Gül on 27/10/14. -// Copyright (c) 2014 Louvre Digital. All rights reserved. +// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved. // #import "UIImage+Crop.h" From 2021cbde677077cad6147deab3e5d2bda613039e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Sun, 24 May 2015 20:57:18 +0300 Subject: [PATCH 11/14] bundle id update --- LLSimpleCameraExampleTests/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LLSimpleCameraExampleTests/Info.plist b/LLSimpleCameraExampleTests/Info.plist index d440397..4097f37 100644 --- a/LLSimpleCameraExampleTests/Info.plist +++ b/LLSimpleCameraExampleTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.louvredigital.$(PRODUCT_NAME:rfc1034identifier) + com.omerfarukgul.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName From fbca46f1fa2b4dceb39e9924cf62c392b2111c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Sun, 24 May 2015 20:59:18 +0300 Subject: [PATCH 12/14] video error handling and small fixes --- LLSimpleCamera/LLSimpleCamera.h | 49 +++++++++++++++++++++------------ LLSimpleCamera/LLSimpleCamera.m | 27 ++++++++++++++---- 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/LLSimpleCamera/LLSimpleCamera.h b/LLSimpleCamera/LLSimpleCamera.h index 0e82a0d..c145c5b 100644 --- a/LLSimpleCamera/LLSimpleCamera.h +++ b/LLSimpleCamera/LLSimpleCamera.h @@ -1,9 +1,9 @@ // // CameraViewController.h -// Frizzbee +// LLSimpleCamera // // Created by Ömer Faruk Gül on 24/10/14. -// Copyright (c) 2014 Louvre Digital. All rights reserved. +// Copyright (c) 2014 Ömer Farul Gül. All rights reserved. // #import @@ -25,7 +25,8 @@ extern NSString *const LLSimpleCameraErrorDomain; typedef enum : NSUInteger { LLSimpleCameraErrorCodeCameraPermission = 10, LLSimpleCameraErrorCodeMicrophonePermission = 11, - LLSimpleCameraErrorCodeSession = 12 + LLSimpleCameraErrorCodeSession = 12, + LLSimpleCameraErrorCodeVideoNotEnabled = 13 } LLSimpleCameraErrorCode; @interface LLSimpleCamera : UIViewController @@ -40,6 +41,12 @@ typedef enum : NSUInteger { */ @property (nonatomic, copy) void (^onError)(LLSimpleCamera *camera, NSError *error); +/** + * Camera quality, set a constants prefixed with AVCaptureSessionPreset. + * Make sure to call before calling -(void)initialize method, otherwise it would be late. + */ +@property (copy, nonatomic) NSString *cameraQuality; + /** * Camera flash mode. */ @@ -109,8 +116,28 @@ typedef enum : NSUInteger { */ - (void)stop; +/** + * Capture an image. + * @param onCapture a block triggered after the capturing the photo. + * @param exactSeenImage If set YES, then the image is cropped to the exact size as the preview. So you get exactly what you see. + */ +-(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture exactSeenImage:(BOOL)exactSeenImage; + +/** + * Capture an image. + * @param onCapture a block triggered after the capturing the photo. + */ +-(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture; + +/* + * Start recording a video. Video is saved to the given url. + */ - (void)startRecordingWithOutputUrl:(NSURL *)url; -- (void)stopRecording:(void (^)(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error))didRecord; + +/** + * Stop recording video with a completion block. + */ +- (void)stopRecording:(void (^)(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error))completionBlock; /** * Attaches the LLSimpleCamera to another view controller with a frame. It basically adds the LLSimpleCamera as a @@ -147,18 +174,4 @@ typedef enum : NSUInteger { */ - (void)alterFocusBox:(CALayer *)layer animation:(CAAnimation *)animation; -/** - * Capture the image. - * @param onCapture a block triggered after the capturing the photo. - * @param exactSeenImage If set YES, then the image is cropped to the exact size as the preview. So you get exactly what you see. - */ --(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture exactSeenImage:(BOOL)exactSeenImage; - -/** - * Capture the image. - * @param onCapture a block triggered after the capturing the photo. - */ --(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture; - - @end diff --git a/LLSimpleCamera/LLSimpleCamera.m b/LLSimpleCamera/LLSimpleCamera.m index ea353ce..20c902b 100644 --- a/LLSimpleCamera/LLSimpleCamera.m +++ b/LLSimpleCamera/LLSimpleCamera.m @@ -1,9 +1,9 @@ // // CameraViewController.m -// Frizzbee +// LLSimpleCamera // // Created by Ömer Faruk Gül on 24/10/14. -// Copyright (c) 2014 Louvre Digital. All rights reserved. +// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved. // #import "LLSimpleCamera.h" @@ -11,7 +11,6 @@ #import "UIImage+FixOrientation.h" @interface LLSimpleCamera () -@property (copy, nonatomic) NSString *cameraQuality; @property (strong, nonatomic) UIView *preview; @property (strong, nonatomic) AVCaptureStillImageOutput *stillImageOutput; @property (strong, nonatomic) AVCaptureSession *session; @@ -40,7 +39,7 @@ - (instancetype)init { } - (instancetype)initWithVideoEnabled:(BOOL)videoEnabled { - self = [self initWithQuality:AVCaptureSessionPresetHigh position:CameraPositionBack videoEnabled:NO]; + self = [self initWithQuality:AVCaptureSessionPresetHigh position:CameraPositionBack videoEnabled:videoEnabled]; if(self) { } @@ -217,7 +216,7 @@ - (void)initialize { [self.session addInput:_videoDeviceInput]; } - // audio + // add audio if video is enabled if(self.videoEnabled) { _audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; _audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_audioCaptureDevice error:&error]; @@ -314,6 +313,19 @@ -(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *m #pragma mark Video Methods - (void)startRecordingWithOutputUrl:(NSURL *)url { + + // check if video is enabled + if(!self.videoEnabled) { + NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain + code:LLSimpleCameraErrorCodeVideoNotEnabled + userInfo:nil]; + if(self.onError) { + self.onError(self, error); + } + + return; + } + if(self.flash == CameraFlashOn) { [self enableTorch:YES]; } @@ -321,6 +333,11 @@ - (void)startRecordingWithOutputUrl:(NSURL *)url { } - (void)stopRecording:(void (^)(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error))completionBlock { + + if(!self.videoEnabled) { + return; + } + self.didRecord = completionBlock; [self.movieFileOutput stopRecording]; } From f551b93c07466cea469285c43572c30f41db0c76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Sun, 24 May 2015 20:59:40 +0300 Subject: [PATCH 13/14] podspec update to 3.0 --- LLSimpleCamera.podspec | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/LLSimpleCamera.podspec b/LLSimpleCamera.podspec index 576205e..e7d86f7 100644 --- a/LLSimpleCamera.podspec +++ b/LLSimpleCamera.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |s| s.name = "LLSimpleCamera" - s.version = "2.2.0" - s.summary = "LLSimpleCamera: A simple customizable camera control." + s.version = "3.0.0" + s.summary = "LLSimpleCamera: A simple customizable camera - video recorder control." s.description = <<-DESC - LLSimpleCamera is a library for creating a customized camera screens similar to snapchat's. You don't have to present the camera in a new view controller. + LLSimpleCamera is a library for creating a customized camera screens similar to snapchat's. You don't have to present the camera in a new view controller. You can capture images or record videos very easily. LLSimpleCamera: -will let you easily capture photos +will let you easily capture photos or record videos handles the position and flash of the camera hides the nitty gritty details from the developer DESC @@ -15,7 +15,7 @@ hides the nitty gritty details from the developer s.license = { :type => 'APACHE', :file => 'LICENSE' } s.author = { "Ömer Faruk Gül" => "omergul123@gmail.com" } s.platform = :ios,'7.0' - s.source = { :git => "https://github.com/omergul123/LLSimpleCamera.git", :tag => "v2.2.0" } + s.source = { :git => "https://github.com/omergul123/LLSimpleCamera.git", :tag => "v3.0.0" } s.source_files = 'LLSimpleCamera/*.{h,m}' s.requires_arc = true s.framework = 'AVFoundation' From c4d019d5ed6d7dbfa7f18c9d1b2c91d784111559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Sun, 24 May 2015 20:59:57 +0300 Subject: [PATCH 14/14] README update --- README.md | 98 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 570d75a..845f434 100755 --- a/README.md +++ b/README.md @@ -1,60 +1,41 @@ -# LLSimpleCamera: A simple customizable camera control +# LLSimpleCamera: A simple customizable camera - video recorder control ![Screenshot](https://raw.githubusercontent.com/omergul123/LLSimpleCamera/master/screenshot.png) -LLSimpleCamera is a library for creating a customized camera screens similar to snapchat's. You don't have to present the camera in a new view controller. +LLSimpleCamera is a library for creating a customized camera - video recorder screens similar to snapchat's. You don't have to present the camera in a new view controller. ###LLSimpleCamera:### -* lets you easily capture photos +* lets you easily capture photos and record videos (finally) * handles the position and flash of the camera * hides the nitty gritty details from the developer * doesn't have to be presented in a new modal view controller, simply can be embedded inside any of your VCs. (like Snapchat) -#### Version 2.2.0 -- camera permissions are supported, if the permission is not given by the user, onError will be triggered. -- camera flash methods are altered. Now you have to call **- (BOOL)updateFlashMode:(CameraFlash)cameraFlash;** -- cameraFlash and cameraPosition property names are simplified to: **flash** and **position**. -- added support for device orientation in case your vc orientation is locked but you want to use the device orientation no matter what. - -#### Version 2.1.1 -- freezing the screen just after the photo is taken for better user experience. - -#### Version 2.1.0 -- added an extra parameter exactSeenImage:(BOOL)exactSeenImage to -capture method to easily get the exact seen image on the screen instead of the raw uncropped image. The default value is NO. -- fixed an orientation bug inside capture method. - -#### Version 2.0.0 -Some significant changes have been made at both internal structure and api. -- added tap to focus feature (it is fully customizable, if you don't like the default layer and animation) -- removed delegates and added blocks -- interface is significantly improved - -#### Version 1.1.1 -- fixed a potential crash scenario if -stop() is called multiple times - -#### Version 1.1.0 -- fixed a problem that sometimes caused a crash after capturing a photo. -- improved code structure, didChangeDevice delegate is now also triggered for the first default device. - ## Install -pod 'LLSimpleCamera', '~> 2.2' +pod 'LLSimpleCamera', '~> 3.0' ## Example usage +Initialize the LLSimpleCamera ```` CGRect screenRect = [[UIScreen mainScreen] bounds]; -// create camera vc -self.camera = [[LLSimpleCamera alloc] initWithQuality:CameraQualityPhoto andPosition:CameraPositionBack]; +// create camera with standard settings +self.camera = [[LLSimpleCamera alloc] init]; + +// camera with video recording capability +self.camera = [[LLSimpleCamera alloc] nitWithVideoEnabled:YES]; +// camera with precise quality, position and video parameters. +self.camera = [[LLSimpleCamera alloc] initWithQuality:AVCaptureSessionPresetHigh + position:CameraPositionBack + videoEnabled:YES]; // attach to the view [self.camera attachToViewController:self withFrame:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)]; ```` To capture a photo: - ```` // capture [self.camera capture:^(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error) { @@ -70,6 +51,22 @@ To capture a photo: }]; ```` +To start recording a video: +```` +// start recording +NSURL *outputURL = [[[self applicationDocumentsDirectory] + URLByAppendingPathComponent:@"test1"] URLByAppendingPathExtension:@"mov"]; +[self.camera startRecordingWithOutputUrl:outputURL]; +```` + +To stop recording the video: +```` +[self.camera stopRecording:^(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error) { + VideoViewController *vc = [[VideoViewController alloc] initWithVideoUrl:outputFileUrl]; + [self.navigationController pushViewController:vc animated:YES]; +}]; +```` + Changing the focus layer and animation: ```` - (void)alterFocusBox:(CALayer *)layer animation:(CAAnimation *)animation; @@ -87,8 +84,39 @@ You should never forget to stop the camera either after the capture block is tri Ömer Faruk Gül -[My LinkedIn Account][2] +[Personal Site][2] +omer@omerfarukgul.com + + [2]: http://omerfarukgul.com + + ## Version History ## + + #### Version 2.2.0 +- camera permissions are supported, if the permission is not given by the user, onError will be triggered. +- camera flash methods are altered. Now you have to call **- (BOOL)updateFlashMode:(CameraFlash)cameraFlash;** +- cameraFlash and cameraPosition property names are simplified to: **flash** and **position**. +- added support for device orientation in case your vc orientation is locked but you want to use the device orientation no matter what. + +#### Version 2.1.1 +- freezing the screen just after the photo is taken for better user experience. + +#### Version 2.1.0 +- added an extra parameter exactSeenImage:(BOOL)exactSeenImage to -capture method to easily get the exact seen image on the screen instead of the raw uncropped image. The default value is NO. +- fixed an orientation bug inside capture method. + +#### Version 2.0.0 +Some significant changes have been made at both internal structure and api. +- added tap to focus feature (it is fully customizable, if you don't like the default layer and animation) +- removed delegates and added blocks +- interface is significantly improved + +#### Version 1.1.1 +- fixed a potential crash scenario if -stop() is called multiple times + +#### Version 1.1.0 +- fixed a problem that sometimes caused a crash after capturing a photo. +- improved code structure, didChangeDevice delegate is now also triggered for the first default device. + - [2]: http://www.linkedin.com/profile/view?id=44437676