AVClub 0.1.4 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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;
|