AVClub 0.1.4 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +34 -15
- data/Rakefile +4 -3
- data/app/camera_controller.rb +25 -27
- data/lib/AVClub/AVClubController.rb +28 -24
- data/lib/AVClub/version.rb +1 -1
- data/lib/avclub.rb +1 -1
- data/vendor/AVClub/{AVClub/AVCamRecorder.h → AVCamRecorder.h} +2 -0
- data/vendor/AVClub/{AVClub/AVCamRecorder.m → AVCamRecorder.m} +23 -17
- data/vendor/AVClub/{AVClub/AVCamUtilities.h → AVCamUtilities.h} +0 -0
- data/vendor/AVClub/{AVClub/AVCamUtilities.m → AVCamUtilities.m} +0 -0
- data/vendor/AVClub/{AVClub/AVClub.h → AVClub.h} +6 -3
- data/vendor/AVClub/{AVClub/AVClub.m → AVClub.m} +104 -94
- metadata +8 -15
- data/vendor/AVClub/AVClub.xcodeproj/project.pbxproj +0 -290
- data/vendor/AVClub/AVClub.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- data/vendor/AVClub/AVClub.xcodeproj/project.xcworkspace/xcuserdata/colinta.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- data/vendor/AVClub/AVClub.xcodeproj/project.xcworkspace/xcuserdata/colinta.xcuserdatad/WorkspaceSettings.xcsettings +0 -10
- data/vendor/AVClub/AVClub.xcodeproj/xcuserdata/colinta.xcuserdatad/xcschemes/AVClub.xcscheme +0 -59
- data/vendor/AVClub/AVClub.xcodeproj/xcuserdata/colinta.xcuserdatad/xcschemes/xcschememanagement.plist +0 -22
- data/vendor/AVClub/AVClub/AVClub-Prefix.pch +0 -9
data/README.md
CHANGED
@@ -12,9 +12,9 @@ I just moved more code into the Manager class, and renamed "AVCamManager" to
|
|
12
12
|
"AVClub", since that's the central "wrapper" class.
|
13
13
|
|
14
14
|
This tool - and AVFoundation in general - is much more low level than the
|
15
|
-
UIImagePickerController (see Camera Programming Topics for iOS). If you're
|
16
|
-
looking for an easy off-the-shelf solution, use
|
17
|
-
UIImagePickerController
|
15
|
+
`UIImagePickerController` (see Camera Programming Topics for iOS). If you're
|
16
|
+
looking for an easy off-the-shelf solution, use `BubbleWrap::Camera` or an
|
17
|
+
instance of `UIImagePickerController`.
|
18
18
|
|
19
19
|
Working with AVFoundation is like holding a dozen loose wires, plugging them all
|
20
20
|
into each other, and hoping that a photo or video comes out the end. If it goes
|
@@ -23,14 +23,14 @@ wrong, lemme know.
|
|
23
23
|
|
24
24
|
The basic process is this:
|
25
25
|
|
26
|
-
Create a view for where you want the
|
27
|
-
|
28
|
-
do it! (creepy! :-P)
|
26
|
+
Create a view-finder, for where you want the preview image to appear. Or don't,
|
27
|
+
it's optional.
|
29
28
|
|
30
29
|
1. Create a "club" - `AVClub.new`.
|
31
30
|
2. Assign your controller as the delegate - `club.delegate = self`.
|
32
|
-
3.
|
33
|
-
stop the session by
|
31
|
+
3. When you're ready, pass the view-finder to AVClub:
|
32
|
+
`club.startInView(viewfinder_view)`. You can start and stop the session by
|
33
|
+
calling `club.stopSession ; club.startSession`
|
34
34
|
|
35
35
|
```ruby
|
36
36
|
def viewDidLoad
|
@@ -41,16 +41,35 @@ def viewDidLoad
|
|
41
41
|
end
|
42
42
|
```
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
You might have noticed that AVClub uses `camelCased` method names, rather than
|
45
|
+
the more rubyesque `snake_case`. This is to distinguish it as an *Objective-C*
|
46
|
+
class. *However*, for convenience, there is an included `AVClubController`
|
47
|
+
class that is a *Ruby* class, and so uses `snake_case`. It adds two methods you
|
48
|
+
can use or refer to: `start_in_view(viewfinder)` (it just passes it on to the
|
49
|
+
`AVClub` object, `@club`) and `rotate_camera_to(orientation:duration:)`.
|
47
50
|
|
48
51
|
```ruby
|
49
52
|
# this method creates the club, assigns it to self.club, and assigns the
|
50
53
|
# viewFinderView that you pass to self.viewFinderView
|
51
|
-
def
|
54
|
+
def viewWillAppear(animated)
|
55
|
+
self.start_in_view(view)
|
56
|
+
end
|
57
|
+
|
58
|
+
# you have to tell AVClub to rotate the image using rotate_camera_to()
|
59
|
+
def willRotateToInterfaceOrientation(to_interface_orientation, duration:duration)
|
60
|
+
# you'll need to adjust the frame yourself!
|
52
61
|
|
53
|
-
|
54
|
-
|
55
|
-
|
62
|
+
case to_interface_orientation
|
63
|
+
when UIInterfaceOrientationLandscapeLeft
|
64
|
+
new_frame = CGRect.new([0, 0], [480, 320])
|
65
|
+
when UIInterfaceOrientationLandscapeRight
|
66
|
+
new_frame = CGRect.new([0, 0], [480, 320])
|
67
|
+
when UIInterfaceOrientationPortrait
|
68
|
+
new_frame = CGRect.new([0, 0], [320, 480])
|
69
|
+
when UIInterfaceOrientationPortraitUpsideDown
|
70
|
+
new_frame = CGRect.new([0, 0], [320, 480])
|
71
|
+
end
|
72
|
+
|
73
|
+
rotate_camera_to(new_frame, orientation: to_interface_orientation, duration:duration)
|
74
|
+
end
|
56
75
|
```
|
data/Rakefile
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
$:.unshift("/Library/RubyMotion/lib")
|
3
3
|
require 'motion/project'
|
4
|
+
if File.exists?(File.expand_path('~/.rubymotion.rb'))
|
5
|
+
require '~/.rubymotion.rb'
|
6
|
+
end
|
4
7
|
|
5
8
|
|
6
9
|
Motion::Project::App.setup do |app|
|
7
10
|
# Use `rake config' to see complete project settings.
|
8
11
|
app.name = 'AVClub-Demo'
|
9
12
|
app.files.insert(0, 'lib/AVClub/AVClubController.rb')
|
10
|
-
# app.files_dependencies 'app/camera_controller.rb' => 'lib/AVClub/AVClubController.rb'
|
11
13
|
|
12
|
-
app.vendor_project('vendor/AVClub', :
|
13
|
-
# app.detect_dependencies = false
|
14
|
+
app.vendor_project('vendor/AVClub', :static, cflags: '-fobjc-arc')
|
14
15
|
app.frameworks.concat [
|
15
16
|
'MediaPlayer',
|
16
17
|
'QuartzCore',
|
data/app/camera_controller.rb
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
class CameraController < AVClubController
|
2
|
-
attr_accessor :record_button, :still_button, :toggle_button
|
2
|
+
attr_accessor :record_button, :still_button, :toggle_button
|
3
3
|
|
4
4
|
def viewDidLoad
|
5
5
|
super
|
6
6
|
self.view.backgroundColor = UIColor.darkGrayColor
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
self.
|
12
|
-
self.view.addSubview(self.viewFinderView)
|
8
|
+
view_finder = UIView.alloc.initWithFrame(UIEdgeInsetsInsetRect(self.view.bounds, [50, 20, 20, 20]))
|
9
|
+
view_finder.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth
|
10
|
+
view_finder.backgroundColor = UIColor.lightGrayColor
|
11
|
+
self.view.addSubview(view_finder)
|
13
12
|
|
14
13
|
### important ###
|
15
|
-
|
14
|
+
start_in_view(view_finder)
|
16
15
|
|
17
16
|
width = 0
|
18
17
|
height = 0
|
@@ -22,7 +21,7 @@ class CameraController < AVClubController
|
|
22
21
|
width += CGRectGetWidth(button.frame)
|
23
22
|
height = CGRectGetHeight(button.frame)
|
24
23
|
|
25
|
-
button.addTarget(self, action: '
|
24
|
+
button.addTarget(self, action: 'toggle_camera:', forControlEvents:UIControlEventTouchUpInside)
|
26
25
|
end
|
27
26
|
width += 10
|
28
27
|
|
@@ -31,7 +30,7 @@ class CameraController < AVClubController
|
|
31
30
|
button.sizeToFit
|
32
31
|
width += CGRectGetWidth(button.frame)
|
33
32
|
|
34
|
-
button.addTarget(self, action: '
|
33
|
+
button.addTarget(self, action: 'toggle_recording:', forControlEvents:UIControlEventTouchUpInside)
|
35
34
|
end
|
36
35
|
width += 10
|
37
36
|
|
@@ -40,7 +39,7 @@ class CameraController < AVClubController
|
|
40
39
|
button.sizeToFit
|
41
40
|
width += CGRectGetWidth(button.frame)
|
42
41
|
|
43
|
-
button.addTarget(self, action: '
|
42
|
+
button.addTarget(self, action: 'capture_still_image:', forControlEvents:UIControlEventTouchUpInside)
|
44
43
|
end
|
45
44
|
|
46
45
|
left = (CGRectGetWidth(self.view.frame) - width) / 2.0
|
@@ -69,27 +68,26 @@ class CameraController < AVClubController
|
|
69
68
|
self.update_button_states
|
70
69
|
|
71
70
|
# Add a single tap gesture to focus on the point tapped, then lock focus
|
72
|
-
singleTap = UITapGestureRecognizer.alloc.initWithTarget(self, action:'
|
71
|
+
singleTap = UITapGestureRecognizer.alloc.initWithTarget(self, action:'tap_to_auto_focus:')
|
73
72
|
singleTap.setDelegate(self)
|
74
73
|
singleTap.setNumberOfTapsRequired(1)
|
75
|
-
|
74
|
+
view_finder.addGestureRecognizer(singleTap)
|
76
75
|
end
|
77
76
|
|
78
|
-
# Auto focus at a particular point. The focus mode will
|
79
|
-
|
80
|
-
def tapToAutoFocus(gestureRecognizer)
|
77
|
+
# Auto focus at a particular point. The focus mode will remain locked.
|
78
|
+
def tap_to_auto_focus(gesture_recognizer)
|
81
79
|
return unless club.videoInput
|
82
80
|
|
83
81
|
if club.videoInput.device.isFocusPointOfInterestSupported
|
84
|
-
tapPoint =
|
82
|
+
tapPoint = gesture_recognizer.locationInView(gesture_recognizer.view)
|
85
83
|
convertedFocusPoint = club.convertToPointOfInterestFromViewCoordinates(tapPoint)
|
86
84
|
club.autoFocusAtPoint(convertedFocusPoint)
|
87
85
|
end
|
88
86
|
end
|
89
87
|
|
90
|
-
# Change to continuous auto focus. The camera will
|
91
|
-
#
|
92
|
-
def tapToContinouslyAutoFocus(
|
88
|
+
# Change to continuous auto focus. The camera will focus at the point choosen,
|
89
|
+
# and then continue to auto focus.
|
90
|
+
def tapToContinouslyAutoFocus(gesture_recognizer)
|
93
91
|
return unless club.videoInput
|
94
92
|
|
95
93
|
if club.videoInput.device.isFocusPointOfInterestSupported
|
@@ -97,7 +95,7 @@ class CameraController < AVClubController
|
|
97
95
|
end
|
98
96
|
end
|
99
97
|
|
100
|
-
def
|
98
|
+
def toggle_camera(sender)
|
101
99
|
# Toggle between cameras when there is more than one
|
102
100
|
club.toggleCamera
|
103
101
|
|
@@ -105,9 +103,9 @@ class CameraController < AVClubController
|
|
105
103
|
club.continuousFocusAtPoint(CGPoint.new(0.5, 0.5))
|
106
104
|
end
|
107
105
|
|
108
|
-
def
|
106
|
+
def toggle_recording(sender)
|
109
107
|
# Start recording if there isn't a recording running. Stop recording if there is.
|
110
|
-
record_button.
|
108
|
+
record_button.enabled = false
|
111
109
|
unless club.recorder.isRecording
|
112
110
|
club.startRecording
|
113
111
|
else
|
@@ -115,11 +113,11 @@ class CameraController < AVClubController
|
|
115
113
|
end
|
116
114
|
end
|
117
115
|
|
118
|
-
def
|
116
|
+
def capture_still_image(sender)
|
119
117
|
return unless still_button.isEnabled
|
120
118
|
|
121
119
|
# Capture a still image
|
122
|
-
still_button.
|
120
|
+
still_button.enabled = false
|
123
121
|
club.captureStillImageAnimated(true)
|
124
122
|
end
|
125
123
|
|
@@ -172,10 +170,10 @@ class CameraController < AVClubController
|
|
172
170
|
update_button_states
|
173
171
|
end
|
174
172
|
|
175
|
-
def willRotateToInterfaceOrientation(
|
173
|
+
def willRotateToInterfaceOrientation(to_interface_duration, duration:duration)
|
176
174
|
super
|
177
175
|
|
178
|
-
case
|
176
|
+
case to_interface_duration
|
179
177
|
when UIInterfaceOrientationLandscapeLeft
|
180
178
|
new_frame = CGRect.new([0, 0], [480, 320])
|
181
179
|
when UIInterfaceOrientationLandscapeRight
|
@@ -187,7 +185,7 @@ class CameraController < AVClubController
|
|
187
185
|
end
|
188
186
|
|
189
187
|
### important ###
|
190
|
-
|
188
|
+
rotate_camera_to(new_frame, orientation:to_interface_duration, duration:duration)
|
191
189
|
end
|
192
190
|
|
193
191
|
end
|
@@ -1,25 +1,25 @@
|
|
1
1
|
class AVClubController < UIViewController
|
2
2
|
attr_accessor :club
|
3
|
-
attr_accessor :
|
3
|
+
attr_accessor :view_finder_view
|
4
4
|
|
5
|
-
def
|
6
|
-
|
5
|
+
def start_in_view(view)
|
6
|
+
@view_finder_view = view
|
7
7
|
|
8
|
-
unless club
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
unless @club
|
9
|
+
@club = AVClub.new
|
10
|
+
@club.delegate = self
|
11
|
+
@club.startInView(view)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
def club(club, didFailWithError:error)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
alert_view = UIAlertView.alloc.initWithTitle(error.localizedDescription,
|
17
|
+
message:error.localizedFailureReason,
|
18
|
+
delegate:nil,
|
19
|
+
cancelButtonTitle:'OK',
|
20
|
+
otherButtonTitles:nil
|
21
|
+
)
|
22
|
+
alert_view.show
|
23
23
|
end
|
24
24
|
|
25
25
|
def club(club, stillImageCaptured:image, error:error)
|
@@ -37,19 +37,19 @@ class AVClubController < UIViewController
|
|
37
37
|
def clubDeviceConfigurationChanged(club)
|
38
38
|
end
|
39
39
|
|
40
|
-
def
|
41
|
-
return unless
|
40
|
+
def rotate_camera_to(new_frame, orientation:to_interface_orientation, duration:duration)
|
41
|
+
return unless @view_finder_view
|
42
42
|
|
43
|
-
|
44
|
-
|
43
|
+
capture_video_preview_layer = nil
|
44
|
+
@view_finder_view.layer.sublayers.each do |layer|
|
45
45
|
if layer.is_a? AVCaptureVideoPreviewLayer
|
46
|
-
|
46
|
+
capture_video_preview_layer = layer
|
47
47
|
break
|
48
48
|
end
|
49
49
|
end
|
50
|
-
return unless
|
50
|
+
return unless capture_video_preview_layer
|
51
51
|
|
52
|
-
case
|
52
|
+
case to_interface_orientation
|
53
53
|
when UIInterfaceOrientationLandscapeLeft
|
54
54
|
rotation = Math::PI / 2
|
55
55
|
when UIInterfaceOrientationLandscapeRight
|
@@ -60,10 +60,14 @@ class AVClubController < UIViewController
|
|
60
60
|
rotation = 2 * Math::PI
|
61
61
|
end
|
62
62
|
|
63
|
-
|
63
|
+
capture_video_preview_layer.masksToBounds = true
|
64
64
|
UIView.animateWithDuration(duration, animations:lambda{
|
65
|
-
|
66
|
-
|
65
|
+
transform = CATransform3DMakeRotation(rotation, 0, 0, 1.0)
|
66
|
+
capture_video_preview_layer.anchorPoint = [0.5, 0.5]
|
67
|
+
capture_video_preview_layer.transform = transform
|
68
|
+
capture_video_preview_layer.frame = new_frame
|
69
|
+
club.orientation = to_interface_orientation
|
67
70
|
})
|
68
71
|
end
|
72
|
+
|
69
73
|
end
|
data/lib/AVClub/version.rb
CHANGED
data/lib/avclub.rb
CHANGED
@@ -21,7 +21,7 @@ Motion::Project::App.setup do |app|
|
|
21
21
|
app.files.insert(insert_point, file)
|
22
22
|
end
|
23
23
|
|
24
|
-
app.vendor_project(File.join(File.dirname(__FILE__), '../vendor/AVClub'), :
|
24
|
+
app.vendor_project(File.join(File.dirname(__FILE__), '../vendor/AVClub'), :static, cflags: '-fobjc-arc')
|
25
25
|
|
26
26
|
app.frameworks.concat [
|
27
27
|
'MediaPlayer',
|
@@ -66,10 +66,10 @@
|
|
66
66
|
AVCaptureMovieFileOutput *aMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
|
67
67
|
if ([aSession canAddOutput:aMovieFileOutput])
|
68
68
|
[aSession addOutput:aMovieFileOutput];
|
69
|
-
|
69
|
+
self.movieFileOutput = aMovieFileOutput;
|
70
70
|
|
71
|
-
|
72
|
-
|
71
|
+
self.session = aSession;
|
72
|
+
self.outputFileURL = anOutputFileURL;
|
73
73
|
}
|
74
74
|
|
75
75
|
return self;
|
@@ -80,34 +80,40 @@
|
|
80
80
|
[[self session] removeOutput:[self movieFileOutput]];
|
81
81
|
}
|
82
82
|
|
83
|
+
- (AVCaptureConnection *)videoConnection
|
84
|
+
{
|
85
|
+
return [AVCamUtilities connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self movieFileOutput] connections]];
|
86
|
+
}
|
87
|
+
|
88
|
+
- (AVCaptureConnection *)audioConnection
|
89
|
+
{
|
90
|
+
return [AVCamUtilities connectionWithMediaType:AVMediaTypeAudio fromConnections:[[self movieFileOutput] connections]];
|
91
|
+
}
|
92
|
+
|
93
|
+
|
83
94
|
-(BOOL)isOrientationSupported
|
84
95
|
{
|
85
|
-
|
86
|
-
return [videoConnection isVideoOrientationSupported];
|
96
|
+
return [self.videoConnection isVideoOrientationSupported];
|
87
97
|
}
|
88
98
|
|
89
99
|
-(void)setOrientation:(AVCaptureVideoOrientation)orientation
|
90
100
|
{
|
91
|
-
|
92
|
-
return [videoConnection setVideoOrientation:orientation];
|
101
|
+
return [self.videoConnection setVideoOrientation:orientation];
|
93
102
|
}
|
94
103
|
|
95
104
|
-(BOOL)isMirrored
|
96
105
|
{
|
97
|
-
|
98
|
-
return [videoConnection isVideoMirrored];
|
106
|
+
return [self.videoConnection isVideoMirrored];
|
99
107
|
}
|
100
108
|
|
101
109
|
-(BOOL)recordsVideo
|
102
110
|
{
|
103
|
-
|
104
|
-
return [videoConnection isActive];
|
111
|
+
return [self.videoConnection isActive];
|
105
112
|
}
|
106
113
|
|
107
114
|
-(BOOL)recordsAudio
|
108
115
|
{
|
109
|
-
|
110
|
-
return [audioConnection isActive];
|
116
|
+
return [self.audioConnection isActive];
|
111
117
|
}
|
112
118
|
|
113
119
|
-(BOOL)isRecording
|
@@ -117,12 +123,11 @@
|
|
117
123
|
|
118
124
|
-(void)startRecordingWithOrientation:(AVCaptureVideoOrientation)videoOrientation;
|
119
125
|
{
|
120
|
-
|
121
|
-
if ( ! videoConnection )
|
126
|
+
if ( ! self.videoConnection )
|
122
127
|
return;
|
123
128
|
|
124
|
-
if ([videoConnection isVideoOrientationSupported])
|
125
|
-
[videoConnection setVideoOrientation:videoOrientation];
|
129
|
+
if ([self.videoConnection isVideoOrientationSupported])
|
130
|
+
[self.videoConnection setVideoOrientation:videoOrientation];
|
126
131
|
|
127
132
|
[[self movieFileOutput] startRecordingToOutputFileURL:[self outputFileURL] recordingDelegate:self];
|
128
133
|
}
|
@@ -134,6 +139,7 @@
|
|
134
139
|
|
135
140
|
@end
|
136
141
|
|
142
|
+
|
137
143
|
@implementation AVCamRecorder (FileOutputDelegate)
|
138
144
|
|
139
145
|
- (void) captureOutput:(AVCaptureFileOutput *)captureOutput
|
File without changes
|
File without changes
|
@@ -1,8 +1,8 @@
|
|
1
1
|
//
|
2
2
|
// AVClub.h
|
3
|
-
// AVClub
|
3
|
+
// AVClub. Based on the AVCam demo by Apple.
|
4
4
|
//
|
5
|
-
// Created by Colin
|
5
|
+
// Created by Colin T.A. Gray on 11/16/12.
|
6
6
|
// Copyright (c) 2012 colinta. All rights reserved.
|
7
7
|
//
|
8
8
|
|
@@ -37,12 +37,15 @@
|
|
37
37
|
- (void) startSession;
|
38
38
|
- (void) stopSession;
|
39
39
|
|
40
|
-
- (CGPoint)convertToPointOfInterestFromViewCoordinates:(CGPoint)viewCoordinates;
|
40
|
+
- (CGPoint) convertToPointOfInterestFromViewCoordinates:(CGPoint)viewCoordinates;
|
41
41
|
- (void) startRecording;
|
42
42
|
- (void) stopRecording;
|
43
43
|
- (void) saveImageToLibrary:(UIImage*)image;
|
44
44
|
- (void) captureStillImage;
|
45
45
|
- (void) captureStillImageAnimated:(BOOL)animated;
|
46
|
+
- (AVCaptureDevice *) frontFacingCamera;
|
47
|
+
- (AVCaptureDevice *) backFacingCamera;
|
48
|
+
- (AVCaptureDevicePosition) currentCamera;
|
46
49
|
- (BOOL) toggleCamera;
|
47
50
|
- (BOOL) toggleCameraAnimated:(BOOL)animated;
|
48
51
|
- (void) autoFocusAtPoint:(CGPoint)point;
|