av_capture 1.0.0
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.
- checksums.yaml +7 -0
- data/.autotest +8 -0
- data/.gemtest +0 -0
- data/CHANGELOG.rdoc +6 -0
- data/Gemfile +7 -0
- data/Manifest.txt +16 -0
- data/README.markdown +94 -0
- data/Rakefile +30 -0
- data/ext/av_capture/connection.m +7 -0
- data/ext/av_capture/device.m +33 -0
- data/ext/av_capture/extconf.rb +5 -0
- data/ext/av_capture/input.m +29 -0
- data/ext/av_capture/maccam.m +38 -0
- data/ext/av_capture/rb_av_dev.h +14 -0
- data/ext/av_capture/session.m +93 -0
- data/ext/av_capture/still_image_output.m +85 -0
- data/lib/av_capture.rb +52 -0
- data/test/test_maccam.rb +116 -0
- metadata +109 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f8e99dad77f6a89bc049ebf0872b2ab163a447c7
|
4
|
+
data.tar.gz: 01122777757c350ff765ffb06ebff748ee54fa78
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f98f29863c002f6a728e6631562bc3dc30e0b77bca77285a3121f296b66a94653ad3da8a2957b9f49c16b896b325c85474256793d1d450c6cda9e06bc8423e5
|
7
|
+
data.tar.gz: 55ca12dc317b176d4b2b302e360b056d472fbbeb1c1abfa63c80eecab9d1bfa4382bbc23abd5e66aa56f5cbabb6ea09fd981ab96b5b5100b3fca365ed451b179
|
data/.autotest
ADDED
data/.gemtest
ADDED
File without changes
|
data/CHANGELOG.rdoc
ADDED
data/Gemfile
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
.autotest
|
2
|
+
CHANGELOG.rdoc
|
3
|
+
Gemfile
|
4
|
+
Manifest.txt
|
5
|
+
README.markdown
|
6
|
+
Rakefile
|
7
|
+
ext/av_capture/connection.m
|
8
|
+
ext/av_capture/device.m
|
9
|
+
ext/av_capture/extconf.rb
|
10
|
+
ext/av_capture/input.m
|
11
|
+
ext/av_capture/maccam.m
|
12
|
+
ext/av_capture/rb_av_dev.h
|
13
|
+
ext/av_capture/session.m
|
14
|
+
ext/av_capture/still_image_output.m
|
15
|
+
lib/av_capture.rb
|
16
|
+
test/test_maccam.rb
|
data/README.markdown
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# AVCapture wrapper
|
2
|
+
|
3
|
+
* https://github.com/tenderlove/av_capture
|
4
|
+
|
5
|
+
## DESCRIPTION:
|
6
|
+
|
7
|
+
Wraps up AVCapture and exposes it to Ruby.
|
8
|
+
|
9
|
+
## FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* Not particularly easy to use right now
|
12
|
+
|
13
|
+
### SYNOPSIS:
|
14
|
+
|
15
|
+
Capture an image:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
session = AVCapture::Session.new # AVCaptureSession
|
19
|
+
dev = AVCapture.devices.find(&:video?) # AVCaptureDevice
|
20
|
+
|
21
|
+
p dev.name
|
22
|
+
p dev.video?
|
23
|
+
output = AVCapture::StillImageOutput.new # AVCaptureOutput subclass
|
24
|
+
session.add_input dev.as_input
|
25
|
+
session.add_output output
|
26
|
+
|
27
|
+
session.run do
|
28
|
+
connection = output.video_connection
|
29
|
+
|
30
|
+
ios = 5.times.map {
|
31
|
+
io = output.capture_on connection
|
32
|
+
sleep 0.5
|
33
|
+
io
|
34
|
+
}
|
35
|
+
|
36
|
+
ios.each_with_index do |io, i|
|
37
|
+
File.open("x_#{i}.jpg", 'wb') { |f| f.write io.data }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
## REQUIREMENTS:
|
43
|
+
|
44
|
+
* You'll need to be running OS X to use this gem.
|
45
|
+
|
46
|
+
* Because this gem depends on Apple's AVFoundation framework for
|
47
|
+
access to the camera, you'll need to install
|
48
|
+
[Xcode](https://itunes.apple.com/us/app/xcode/id497799835) and
|
49
|
+
its [command-line](http://stackoverflow.com/a/9329325/798224)
|
50
|
+
tools before building or installing.
|
51
|
+
|
52
|
+
## INSTALL:
|
53
|
+
|
54
|
+
Compile and run the test suite to make sure you have all the necessary
|
55
|
+
compile-time dependencies:
|
56
|
+
|
57
|
+
```sh
|
58
|
+
bundle
|
59
|
+
rake
|
60
|
+
```
|
61
|
+
|
62
|
+
Install the gem:
|
63
|
+
|
64
|
+
```sh
|
65
|
+
rake install_gem
|
66
|
+
```
|
67
|
+
|
68
|
+
You may need to run `sudo rake install_gem` depending on your Ruby
|
69
|
+
installation.
|
70
|
+
|
71
|
+
## LICENSE:
|
72
|
+
|
73
|
+
(The MIT License)
|
74
|
+
|
75
|
+
Copyright (c) 2013 Aaron Patterson
|
76
|
+
|
77
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
78
|
+
a copy of this software and associated documentation files (the
|
79
|
+
'Software'), to deal in the Software without restriction, including
|
80
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
81
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
82
|
+
permit persons to whom the Software is furnished to do so, subject to
|
83
|
+
the following conditions:
|
84
|
+
|
85
|
+
The above copyright notice and this permission notice shall be
|
86
|
+
included in all copies or substantial portions of the Software.
|
87
|
+
|
88
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
89
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
90
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
91
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
92
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
93
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
94
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require "rake/extensiontask"
|
6
|
+
|
7
|
+
Hoe.plugins.delete :rubyforge
|
8
|
+
Hoe.plugin :minitest
|
9
|
+
Hoe.plugin :gemspec # `gem install hoe-gemspec`
|
10
|
+
Hoe.plugin :git # `gem install hoe-git`
|
11
|
+
|
12
|
+
Hoe.spec 'av_capture' do
|
13
|
+
developer('Aaron Patterson', 'tenderlove@ruby-lang.org')
|
14
|
+
self.readme_file = 'README.markdown'
|
15
|
+
self.history_file = 'CHANGELOG.rdoc'
|
16
|
+
self.extra_rdoc_files = FileList['*.{rdoc,markdown}']
|
17
|
+
|
18
|
+
self.spec_extras = {
|
19
|
+
:extensions => ["ext/av_capture/extconf.rb"],
|
20
|
+
:required_ruby_version => '>= 2.0.0'
|
21
|
+
}
|
22
|
+
|
23
|
+
Rake::ExtensionTask.new "av_capture", spec do |ext|
|
24
|
+
ext.lib_dir = File.join(*['lib', ENV['FAT_DIR']].compact)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
task :test => [:compile]
|
29
|
+
|
30
|
+
# vim: syntax=ruby
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#include <rb_av_dev.h>
|
2
|
+
|
3
|
+
static VALUE rb_name(VALUE self) {
|
4
|
+
AVCaptureDevice * dev;
|
5
|
+
|
6
|
+
Data_Get_Struct(self, AVCaptureDevice, dev);
|
7
|
+
|
8
|
+
return rb_enc_associate(rb_str_new2([[dev localizedName] UTF8String]),
|
9
|
+
rb_utf8_encoding());
|
10
|
+
}
|
11
|
+
|
12
|
+
static VALUE has_media_type_p(VALUE self, VALUE media_type) {
|
13
|
+
AVCaptureDevice * dev;
|
14
|
+
|
15
|
+
Data_Get_Struct(self, AVCaptureDevice, dev);
|
16
|
+
|
17
|
+
NSString * mt = [NSString stringWithCString: StringValuePtr(media_type)
|
18
|
+
encoding: NSUTF8StringEncoding];
|
19
|
+
|
20
|
+
if ([dev hasMediaType: mt]) {
|
21
|
+
return Qtrue;
|
22
|
+
} else {
|
23
|
+
return Qfalse;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
VALUE Init_device(VALUE outer) {
|
28
|
+
VALUE rb_cAVDevice = rb_define_class_under(outer, "Device", rb_cObject);
|
29
|
+
rb_define_method(rb_cAVDevice, "name", rb_name, 0);
|
30
|
+
rb_define_method(rb_cAVDevice, "has_media_type?", has_media_type_p, 1);
|
31
|
+
|
32
|
+
return rb_cAVDevice;
|
33
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#include <rb_av_dev.h>
|
2
|
+
|
3
|
+
static VALUE initialize(VALUE self, VALUE dev) {
|
4
|
+
AVCaptureDeviceInput * input;
|
5
|
+
AVCaptureDevice * device;
|
6
|
+
|
7
|
+
Data_Get_Struct(self, AVCaptureDeviceInput, input);
|
8
|
+
Data_Get_Struct(dev, AVCaptureDevice, device);
|
9
|
+
|
10
|
+
[input initWithDevice:device error: nil];
|
11
|
+
|
12
|
+
return self;
|
13
|
+
}
|
14
|
+
|
15
|
+
static VALUE allocate(VALUE klass) {
|
16
|
+
AVCaptureDeviceInput *input = [AVCaptureDeviceInput alloc];
|
17
|
+
|
18
|
+
return Data_Wrap_Struct(klass, 0, 0, input);
|
19
|
+
}
|
20
|
+
|
21
|
+
VALUE Init_input(VALUE outer) {
|
22
|
+
VALUE rb_cDeviceInput = rb_define_class_under(outer, "DeviceInput", rb_cObject);
|
23
|
+
|
24
|
+
rb_define_alloc_func(rb_cDeviceInput, allocate);
|
25
|
+
|
26
|
+
rb_define_method(rb_cDeviceInput, "initialize", initialize, 1);
|
27
|
+
|
28
|
+
return rb_cDeviceInput;
|
29
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#include <rb_av_dev.h>
|
2
|
+
|
3
|
+
VALUE rb_cStillImageOutput;
|
4
|
+
VALUE rb_cAVDevice;
|
5
|
+
|
6
|
+
static void rb_release(id object) {
|
7
|
+
[object release];
|
8
|
+
}
|
9
|
+
|
10
|
+
static VALUE rb_devices(VALUE klass) {
|
11
|
+
VALUE devs;
|
12
|
+
NSArray * list = [AVCaptureDevice devices];
|
13
|
+
|
14
|
+
devs = rb_ary_new2([list count]);
|
15
|
+
|
16
|
+
for (id object in list) {
|
17
|
+
[object retain];
|
18
|
+
VALUE dev = Data_Wrap_Struct(rb_cAVDevice, 0, rb_release, object);
|
19
|
+
rb_ary_push(devs, dev);
|
20
|
+
}
|
21
|
+
|
22
|
+
return devs;
|
23
|
+
}
|
24
|
+
|
25
|
+
void Init_av_capture() {
|
26
|
+
VALUE rb_cAVCapture = rb_define_module("AVCapture");
|
27
|
+
|
28
|
+
rb_cAVDevice = Init_device(rb_cAVCapture);
|
29
|
+
|
30
|
+
rb_cStillImageOutput = Init_still_image_output(rb_cAVCapture,
|
31
|
+
Init_connection(rb_cAVCapture));
|
32
|
+
|
33
|
+
Init_input(rb_cAVCapture);
|
34
|
+
Init_session(rb_cAVCapture);
|
35
|
+
|
36
|
+
rb_define_singleton_method(rb_cAVCapture, "devices", rb_devices, 0);
|
37
|
+
rb_define_const(rb_cAVCapture, "AVMediaTypeVideo", rb_str_new2([AVMediaTypeVideo UTF8String]));
|
38
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#ifndef _RB_AV_DEV_H
|
2
|
+
#define _RB_AV_DEV_H
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
#include <ruby/encoding.h>
|
6
|
+
#import <AVFoundation/AVFoundation.h>
|
7
|
+
|
8
|
+
VALUE Init_device(VALUE outer);
|
9
|
+
VALUE Init_still_image_output(VALUE outer, VALUE conn);
|
10
|
+
VALUE Init_connection(VALUE outer);
|
11
|
+
VALUE Init_session(VALUE outer);
|
12
|
+
VALUE Init_input(VALUE outer);
|
13
|
+
|
14
|
+
#endif
|
@@ -0,0 +1,93 @@
|
|
1
|
+
#include <rb_av_dev.h>
|
2
|
+
|
3
|
+
static VALUE can_add_output_p(VALUE self, VALUE output) {
|
4
|
+
AVCaptureSession * session;
|
5
|
+
AVCaptureOutput * op;
|
6
|
+
|
7
|
+
Data_Get_Struct(self, AVCaptureSession, session);
|
8
|
+
Data_Get_Struct(output, AVCaptureOutput, op);
|
9
|
+
|
10
|
+
if ([session canAddOutput:op]) {
|
11
|
+
return Qtrue;
|
12
|
+
} else {
|
13
|
+
return Qfalse;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
static VALUE add_output(VALUE self, VALUE output) {
|
18
|
+
AVCaptureSession * session;
|
19
|
+
AVCaptureOutput * op;
|
20
|
+
|
21
|
+
Data_Get_Struct(self, AVCaptureSession, session);
|
22
|
+
Data_Get_Struct(output, AVCaptureOutput, op);
|
23
|
+
|
24
|
+
[session addOutput:op];
|
25
|
+
|
26
|
+
return self;
|
27
|
+
}
|
28
|
+
|
29
|
+
static VALUE can_add_input_p(VALUE self, VALUE input) {
|
30
|
+
AVCaptureSession * session;
|
31
|
+
AVCaptureInput * in;
|
32
|
+
|
33
|
+
Data_Get_Struct(self, AVCaptureSession, session);
|
34
|
+
Data_Get_Struct(input, AVCaptureInput, in);
|
35
|
+
|
36
|
+
if ([session canAddInput:in]) {
|
37
|
+
return Qtrue;
|
38
|
+
} else {
|
39
|
+
return Qfalse;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
static VALUE add_input(VALUE self, VALUE input) {
|
44
|
+
AVCaptureSession * session;
|
45
|
+
AVCaptureInput * in;
|
46
|
+
|
47
|
+
Data_Get_Struct(self, AVCaptureSession, session);
|
48
|
+
Data_Get_Struct(input, AVCaptureInput, in);
|
49
|
+
|
50
|
+
[session addInput:in];
|
51
|
+
|
52
|
+
return self;
|
53
|
+
}
|
54
|
+
|
55
|
+
static VALUE start_running(VALUE self) {
|
56
|
+
AVCaptureSession * session;
|
57
|
+
|
58
|
+
Data_Get_Struct(self, AVCaptureSession, session);
|
59
|
+
|
60
|
+
[session startRunning];
|
61
|
+
|
62
|
+
return self;
|
63
|
+
}
|
64
|
+
|
65
|
+
static VALUE stop_running(VALUE self) {
|
66
|
+
AVCaptureSession * session;
|
67
|
+
|
68
|
+
Data_Get_Struct(self, AVCaptureSession, session);
|
69
|
+
|
70
|
+
[session stopRunning];
|
71
|
+
|
72
|
+
return self;
|
73
|
+
}
|
74
|
+
|
75
|
+
static VALUE allocate(VALUE klass) {
|
76
|
+
AVCaptureSession *session = [[AVCaptureSession alloc] init];
|
77
|
+
|
78
|
+
return Data_Wrap_Struct(klass, 0, 0, session);
|
79
|
+
}
|
80
|
+
|
81
|
+
VALUE Init_session(VALUE outer) {
|
82
|
+
VALUE rb_cSession = rb_define_class_under(outer, "Session", rb_cObject);
|
83
|
+
|
84
|
+
rb_define_alloc_func(rb_cSession, allocate);
|
85
|
+
rb_define_method(rb_cSession, "can_add_output?", can_add_output_p, 1);
|
86
|
+
rb_define_method(rb_cSession, "add_output", add_output, 1);
|
87
|
+
rb_define_method(rb_cSession, "can_add_input?", can_add_input_p, 1);
|
88
|
+
rb_define_method(rb_cSession, "add_input", add_input, 1);
|
89
|
+
rb_define_method(rb_cSession, "start_running!", start_running, 0);
|
90
|
+
rb_define_method(rb_cSession, "stop_running!", stop_running, 0);
|
91
|
+
|
92
|
+
return rb_cSession;
|
93
|
+
}
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#include <rb_av_dev.h>
|
2
|
+
|
3
|
+
static VALUE rb_cAVConnection;
|
4
|
+
|
5
|
+
static VALUE rb_connect(VALUE self, VALUE media_type) {
|
6
|
+
AVCaptureOutput * capture;
|
7
|
+
|
8
|
+
Data_Get_Struct(self, AVCaptureOutput, capture);
|
9
|
+
|
10
|
+
NSString * mt = [NSString stringWithCString: StringValuePtr(media_type)
|
11
|
+
encoding: NSUTF8StringEncoding];
|
12
|
+
|
13
|
+
AVCaptureConnection * conn = [capture connectionWithMediaType:mt];
|
14
|
+
|
15
|
+
if (conn) {
|
16
|
+
return Data_Wrap_Struct(rb_cAVConnection, 0, 0, conn);
|
17
|
+
} else {
|
18
|
+
return Qnil;
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
static VALUE connections(VALUE self) {
|
23
|
+
AVCaptureStillImageOutput *output;
|
24
|
+
VALUE conns;
|
25
|
+
|
26
|
+
Data_Get_Struct(self, AVCaptureStillImageOutput, output);
|
27
|
+
NSArray * connections = [output connections];
|
28
|
+
|
29
|
+
conns = rb_ary_new2([connections count]);
|
30
|
+
|
31
|
+
for (id object in connections) {
|
32
|
+
VALUE conn = Data_Wrap_Struct(rb_cAVConnection, 0, 0, object);
|
33
|
+
rb_ary_push(conns, conn);
|
34
|
+
}
|
35
|
+
|
36
|
+
return conns;
|
37
|
+
}
|
38
|
+
|
39
|
+
static VALUE capture(VALUE self, VALUE conn) {
|
40
|
+
int imagePipes[2];
|
41
|
+
AVCaptureStillImageOutput *output;
|
42
|
+
AVCaptureConnection *connection;
|
43
|
+
|
44
|
+
Data_Get_Struct(self, AVCaptureStillImageOutput, output);
|
45
|
+
Data_Get_Struct(conn, AVCaptureConnection, connection);
|
46
|
+
|
47
|
+
rb_pipe(imagePipes);
|
48
|
+
int wrt = imagePipes[1];
|
49
|
+
[output captureStillImageAsynchronouslyFromConnection: connection
|
50
|
+
completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
|
51
|
+
if (imageDataSampleBuffer != NULL) {
|
52
|
+
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
|
53
|
+
write(wrt, [imageData bytes], [imageData length]);
|
54
|
+
close(wrt);
|
55
|
+
} else {
|
56
|
+
rb_raise(rb_eRuntimeError, "%s", [[error localizedDescription] UTF8String]);
|
57
|
+
}
|
58
|
+
}];
|
59
|
+
return INT2NUM(imagePipes[0]);
|
60
|
+
}
|
61
|
+
|
62
|
+
static VALUE allocate(VALUE klass) {
|
63
|
+
AVCaptureStillImageOutput *output = [[AVCaptureStillImageOutput alloc] init];
|
64
|
+
NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
|
65
|
+
AVVideoCodecJPEG, AVVideoCodecKey,
|
66
|
+
nil];
|
67
|
+
[output setOutputSettings:outputSettings];
|
68
|
+
[outputSettings release];
|
69
|
+
|
70
|
+
return Data_Wrap_Struct(klass, 0, 0, output);
|
71
|
+
}
|
72
|
+
|
73
|
+
VALUE Init_still_image_output(VALUE outer, VALUE conn) {
|
74
|
+
rb_cAVConnection = conn;
|
75
|
+
|
76
|
+
VALUE rb_cStillImageOutput = rb_define_class_under(outer, "StillImageOutput", rb_cObject);
|
77
|
+
|
78
|
+
rb_define_alloc_func(rb_cStillImageOutput, allocate);
|
79
|
+
|
80
|
+
rb_define_method(rb_cStillImageOutput, "connect", rb_connect, 1);
|
81
|
+
rb_define_method(rb_cStillImageOutput, "connections", connections, 0);
|
82
|
+
rb_define_method(rb_cStillImageOutput, "capture_still_image", capture, 1);
|
83
|
+
|
84
|
+
return rb_cStillImageOutput;
|
85
|
+
}
|
data/lib/av_capture.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'av_capture.so'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module AVCapture
|
5
|
+
VERSION = '1.0.0'
|
6
|
+
|
7
|
+
class Device
|
8
|
+
def video?
|
9
|
+
has_media_type? AVCapture::AVMediaTypeVideo
|
10
|
+
end
|
11
|
+
|
12
|
+
def as_input
|
13
|
+
AVCapture::DeviceInput.new self
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class ImagePromise
|
18
|
+
def initialize io
|
19
|
+
@io = io
|
20
|
+
@data = nil
|
21
|
+
@mutex = Mutex.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_io; @io; end
|
25
|
+
|
26
|
+
def data
|
27
|
+
@data || @mutex.synchronize do
|
28
|
+
@data ||= @io.read.tap { @io.close }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
alias :read :data
|
32
|
+
end
|
33
|
+
|
34
|
+
class StillImageOutput
|
35
|
+
def video_connection
|
36
|
+
connect AVCapture::AVMediaTypeVideo
|
37
|
+
end
|
38
|
+
|
39
|
+
def capture_on connection
|
40
|
+
ImagePromise.new IO.new capture_still_image connection
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Session
|
45
|
+
def run
|
46
|
+
start_running!
|
47
|
+
yield
|
48
|
+
ensure
|
49
|
+
stop_running!
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/test/test_maccam.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'av_capture'
|
3
|
+
|
4
|
+
class TestAVCapture < MiniTest::Test
|
5
|
+
def device
|
6
|
+
AVCapture.devices.find(&:video?)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_output
|
10
|
+
sio = AVCapture::StillImageOutput.new
|
11
|
+
assert_equal 0, sio.connections.length
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_session
|
15
|
+
session = AVCapture::Session.new
|
16
|
+
sio = AVCapture::StillImageOutput.new
|
17
|
+
assert session.can_add_output?(sio)
|
18
|
+
session.add_output sio
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_add_input
|
22
|
+
session = AVCapture::Session.new
|
23
|
+
dev = device
|
24
|
+
input = AVCapture::DeviceInput.new dev
|
25
|
+
assert session.can_add_input?(input)
|
26
|
+
session.add_input input
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_as_input
|
30
|
+
assert_kind_of AVCapture::DeviceInput, device.as_input
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_add_io
|
34
|
+
session = AVCapture::Session.new
|
35
|
+
dev = device
|
36
|
+
input = AVCapture::DeviceInput.new dev
|
37
|
+
output = AVCapture::StillImageOutput.new
|
38
|
+
session.add_input input
|
39
|
+
session.add_output output
|
40
|
+
assert_equal 1, output.connections.length
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_video_connection
|
44
|
+
session = AVCapture::Session.new
|
45
|
+
dev = device
|
46
|
+
input = AVCapture::DeviceInput.new dev
|
47
|
+
output = AVCapture::StillImageOutput.new
|
48
|
+
session.add_input input
|
49
|
+
session.add_output output
|
50
|
+
|
51
|
+
assert_kind_of AVCapture::Connection, output.video_connection
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_captureStillImageAsynchronouslyFromConnection
|
55
|
+
session = AVCapture::Session.new
|
56
|
+
dev = device
|
57
|
+
input = AVCapture::DeviceInput.new dev
|
58
|
+
output = AVCapture::StillImageOutput.new
|
59
|
+
session.add_input input
|
60
|
+
session.add_output output
|
61
|
+
|
62
|
+
connection = output.connect AVCapture::AVMediaTypeVideo
|
63
|
+
|
64
|
+
session.start_running!
|
65
|
+
pipe_fd = output.capture_still_image connection
|
66
|
+
io = IO.new pipe_fd
|
67
|
+
IO.select([io])
|
68
|
+
assert io.read
|
69
|
+
io.close
|
70
|
+
session.stop_running!
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_capture_on
|
74
|
+
session = AVCapture::Session.new
|
75
|
+
dev = device
|
76
|
+
output = AVCapture::StillImageOutput.new
|
77
|
+
session.add_input dev.as_input
|
78
|
+
session.add_output output
|
79
|
+
|
80
|
+
session.run do
|
81
|
+
connection = output.video_connection
|
82
|
+
pic = output.capture_on connection
|
83
|
+
assert pic.data
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_select_on_pic
|
88
|
+
session = AVCapture::Session.new
|
89
|
+
dev = device
|
90
|
+
output = AVCapture::StillImageOutput.new
|
91
|
+
session.add_input dev.as_input
|
92
|
+
session.add_output output
|
93
|
+
|
94
|
+
session.run do
|
95
|
+
connection = output.video_connection
|
96
|
+
pic = output.capture_on connection
|
97
|
+
rd, = IO.select([pic])
|
98
|
+
assert rd.first.read
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_runblock
|
103
|
+
actions = []
|
104
|
+
klass = Class.new(AVCapture::Session) do
|
105
|
+
define_method(:start_running!) {
|
106
|
+
actions << :start_running
|
107
|
+
}
|
108
|
+
define_method(:stop_running!) {
|
109
|
+
actions << :stop_running
|
110
|
+
}
|
111
|
+
end
|
112
|
+
session = klass.new
|
113
|
+
session.run { actions << :run }
|
114
|
+
assert_equal [:start_running, :run, :stop_running], actions
|
115
|
+
end
|
116
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: av_capture
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Patterson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-12-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.2'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rdoc
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: hoe
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.6'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.6'
|
55
|
+
description: Wraps up AVCapture and exposes it to Ruby.
|
56
|
+
email:
|
57
|
+
- tenderlove@ruby-lang.org
|
58
|
+
executables: []
|
59
|
+
extensions:
|
60
|
+
- ext/av_capture/extconf.rb
|
61
|
+
extra_rdoc_files:
|
62
|
+
- CHANGELOG.rdoc
|
63
|
+
- Manifest.txt
|
64
|
+
- README.markdown
|
65
|
+
files:
|
66
|
+
- ".autotest"
|
67
|
+
- CHANGELOG.rdoc
|
68
|
+
- Gemfile
|
69
|
+
- Manifest.txt
|
70
|
+
- README.markdown
|
71
|
+
- Rakefile
|
72
|
+
- ext/av_capture/connection.m
|
73
|
+
- ext/av_capture/device.m
|
74
|
+
- ext/av_capture/extconf.rb
|
75
|
+
- ext/av_capture/input.m
|
76
|
+
- ext/av_capture/maccam.m
|
77
|
+
- ext/av_capture/rb_av_dev.h
|
78
|
+
- ext/av_capture/session.m
|
79
|
+
- ext/av_capture/still_image_output.m
|
80
|
+
- lib/av_capture.rb
|
81
|
+
- test/test_maccam.rb
|
82
|
+
- ".gemtest"
|
83
|
+
homepage: https://github.com/tenderlove/av_capture
|
84
|
+
licenses: []
|
85
|
+
metadata: {}
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options:
|
88
|
+
- "--main"
|
89
|
+
- README.markdown
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 2.0.0
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubyforge_project: av_capture
|
104
|
+
rubygems_version: 2.0.2
|
105
|
+
signing_key:
|
106
|
+
specification_version: 4
|
107
|
+
summary: Wraps up AVCapture and exposes it to Ruby.
|
108
|
+
test_files:
|
109
|
+
- test/test_maccam.rb
|