rays 0.1.16 → 0.1.17
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 +4 -4
- data/.doc/ext/rays/camera.cpp +86 -3
- data/VERSION +1 -1
- data/ext/rays/bitmap.cpp +1 -1
- data/ext/rays/camera.cpp +98 -6
- data/include/rays/camera.h +26 -1
- data/lib/rays/camera.rb +5 -2
- data/rays.gemspec +2 -2
- data/src/ios/bitmap.h +5 -3
- data/src/ios/bitmap.mm +9 -5
- data/src/ios/camera.mm +319 -45
- data/src/ios/helper.h +2 -2
- data/src/osx/bitmap.h +3 -1
- data/src/osx/bitmap.mm +9 -5
- data/src/osx/camera.mm +260 -45
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b9970ac7078fc1ff19c2039b5d9c3714eeaaba98d5825e374639707231fe212
|
4
|
+
data.tar.gz: 12d43f68907b92bc4fcc293273dfaf1353e17006654e245973d3866f31cac2de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f732d776a9cf8940d22dde937d72d25a38fda8c8842484d525ae105c0ce591dd20b6e10742418e708c60d22b29e44ab5129649538f7593ad834a38ee9cd54a4
|
7
|
+
data.tar.gz: 42d6400febd65098c2ccc37bafde776ad0b42129996e7edbfc74f9d8862622e3439389fcbbbe3788f5f62c4298dad30d0981df45726874dfb41f47047d9d7117
|
data/.doc/ext/rays/camera.cpp
CHANGED
@@ -19,11 +19,14 @@ VALUE alloc(VALUE klass)
|
|
19
19
|
}
|
20
20
|
|
21
21
|
static
|
22
|
-
VALUE
|
22
|
+
VALUE setup(VALUE self, VALUE device_name, VALUE min_width, VALUE min_height, VALUE resize, VALUE crop)
|
23
23
|
{
|
24
24
|
RUCY_CHECK_OBJ(Rays::Camera, self);
|
25
25
|
|
26
|
-
*THIS = Rays::Camera(
|
26
|
+
*THIS = Rays::Camera(
|
27
|
+
device_name ? to<const char*>(device_name) : NULL,
|
28
|
+
to<int>(min_width), to<int>(min_height),
|
29
|
+
to<bool>(resize), to<bool>(crop));
|
27
30
|
return self;
|
28
31
|
}
|
29
32
|
|
@@ -48,6 +51,66 @@ VALUE is_active(VALUE self)
|
|
48
51
|
return value(THIS->is_active());
|
49
52
|
}
|
50
53
|
|
54
|
+
static
|
55
|
+
VALUE set_min_width(VALUE self, VALUE width)
|
56
|
+
{
|
57
|
+
CHECK;
|
58
|
+
THIS->set_min_width(to<int>(width));
|
59
|
+
return value(THIS->min_width());
|
60
|
+
}
|
61
|
+
|
62
|
+
static
|
63
|
+
VALUE min_width(VALUE self)
|
64
|
+
{
|
65
|
+
CHECK;
|
66
|
+
return value(THIS->min_width());
|
67
|
+
}
|
68
|
+
|
69
|
+
static
|
70
|
+
VALUE set_min_height(VALUE self, VALUE height)
|
71
|
+
{
|
72
|
+
CHECK;
|
73
|
+
THIS->set_min_height(to<int>(height));
|
74
|
+
return value(THIS->min_height());
|
75
|
+
}
|
76
|
+
|
77
|
+
static
|
78
|
+
VALUE min_height(VALUE self)
|
79
|
+
{
|
80
|
+
CHECK;
|
81
|
+
return value(THIS->min_height());
|
82
|
+
}
|
83
|
+
|
84
|
+
static
|
85
|
+
VALUE set_resize(VALUE self, VALUE resize)
|
86
|
+
{
|
87
|
+
CHECK;
|
88
|
+
THIS->set_resize(to<bool>(resize));
|
89
|
+
return value(THIS->is_resize());
|
90
|
+
}
|
91
|
+
|
92
|
+
static
|
93
|
+
VALUE is_resize(VALUE self)
|
94
|
+
{
|
95
|
+
CHECK;
|
96
|
+
return value(THIS->is_resize());
|
97
|
+
}
|
98
|
+
|
99
|
+
static
|
100
|
+
VALUE set_crop(VALUE self, VALUE crop)
|
101
|
+
{
|
102
|
+
CHECK;
|
103
|
+
THIS->set_crop(to<bool>(crop));
|
104
|
+
return value(THIS->is_crop());
|
105
|
+
}
|
106
|
+
|
107
|
+
static
|
108
|
+
VALUE is_crop(VALUE self)
|
109
|
+
{
|
110
|
+
CHECK;
|
111
|
+
return value(THIS->is_crop());
|
112
|
+
}
|
113
|
+
|
51
114
|
static
|
52
115
|
VALUE image(VALUE self)
|
53
116
|
{
|
@@ -56,6 +119,17 @@ VALUE image(VALUE self)
|
|
56
119
|
return img ? value(*img) : nil();
|
57
120
|
}
|
58
121
|
|
122
|
+
static
|
123
|
+
VALUE device_names(VALUE self)
|
124
|
+
{
|
125
|
+
auto names = Rays::get_camera_device_names();
|
126
|
+
|
127
|
+
std::vector<Value> v;
|
128
|
+
for (auto it = names.begin(), end = names.end(); it != end; ++it)
|
129
|
+
v.emplace_back(value(it->c_str()));
|
130
|
+
return value(v.size(), &v[0]);
|
131
|
+
}
|
132
|
+
|
59
133
|
|
60
134
|
static Class cCamera;
|
61
135
|
|
@@ -66,11 +140,20 @@ Init_camera ()
|
|
66
140
|
|
67
141
|
cCamera = rb_define_class_under(mRays, "Camera", rb_cObject);
|
68
142
|
rb_define_alloc_func(cCamera, alloc);
|
69
|
-
rb_define_private_method(cCamera, "
|
143
|
+
rb_define_private_method(cCamera, "setup", RUBY_METHOD_FUNC(setup), 5);
|
70
144
|
rb_define_method(cCamera, "start", RUBY_METHOD_FUNC(start), 0);
|
71
145
|
rb_define_method(cCamera, "stop", RUBY_METHOD_FUNC(stop), 0);
|
72
146
|
cCamera.define_method("active?", is_active);
|
147
|
+
rb_define_method(cCamera, "min_width=", RUBY_METHOD_FUNC(set_min_width), 1);
|
148
|
+
rb_define_method(cCamera, "min_width", RUBY_METHOD_FUNC(min_width), 0);
|
149
|
+
rb_define_method(cCamera, "min_height=", RUBY_METHOD_FUNC(set_min_height), 1);
|
150
|
+
rb_define_method(cCamera, "min_height", RUBY_METHOD_FUNC(min_height), 0);
|
151
|
+
rb_define_method(cCamera, "resize=", RUBY_METHOD_FUNC(set_resize), 1);
|
152
|
+
cCamera.define_method("resize?", is_resize);
|
153
|
+
rb_define_method(cCamera, "crop=", RUBY_METHOD_FUNC(set_crop), 1);
|
154
|
+
cCamera.define_method("crop?", is_crop);
|
73
155
|
rb_define_method(cCamera, "image", RUBY_METHOD_FUNC(image), 0);
|
156
|
+
rb_define_module_function(cCamera, "device_names", RUBY_METHOD_FUNC(device_names), 0);
|
74
157
|
}
|
75
158
|
|
76
159
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.17
|
data/ext/rays/bitmap.cpp
CHANGED
@@ -110,7 +110,7 @@ Init_bitmap ()
|
|
110
110
|
cBitmap.define_alloc_func(alloc);
|
111
111
|
cBitmap.define_private_method("initialize", initialize);
|
112
112
|
cBitmap.define_private_method("initialize_copy", initialize_copy);
|
113
|
-
cBitmap.define_method("width",
|
113
|
+
cBitmap.define_method("width", width);
|
114
114
|
cBitmap.define_method("height", height);
|
115
115
|
cBitmap.define_method("color_space", color_space);
|
116
116
|
cBitmap.define_method("[]=", set_at);
|
data/ext/rays/camera.cpp
CHANGED
@@ -20,11 +20,14 @@ RUCY_DEF_ALLOC(alloc, klass)
|
|
20
20
|
RUCY_END
|
21
21
|
|
22
22
|
static
|
23
|
-
|
23
|
+
RUCY_DEF5(setup, device_name, min_width, min_height, resize, crop)
|
24
24
|
{
|
25
25
|
RUCY_CHECK_OBJ(Rays::Camera, self);
|
26
26
|
|
27
|
-
*THIS = Rays::Camera(
|
27
|
+
*THIS = Rays::Camera(
|
28
|
+
device_name ? to<const char*>(device_name) : NULL,
|
29
|
+
to<int>(min_width), to<int>(min_height),
|
30
|
+
to<bool>(resize), to<bool>(crop));
|
28
31
|
return self;
|
29
32
|
}
|
30
33
|
RUCY_END
|
@@ -53,6 +56,74 @@ RUCY_DEF0(is_active)
|
|
53
56
|
}
|
54
57
|
RUCY_END
|
55
58
|
|
59
|
+
static
|
60
|
+
RUCY_DEF1(set_min_width, width)
|
61
|
+
{
|
62
|
+
CHECK;
|
63
|
+
THIS->set_min_width(to<int>(width));
|
64
|
+
return value(THIS->min_width());
|
65
|
+
}
|
66
|
+
RUCY_END
|
67
|
+
|
68
|
+
static
|
69
|
+
RUCY_DEF0(min_width)
|
70
|
+
{
|
71
|
+
CHECK;
|
72
|
+
return value(THIS->min_width());
|
73
|
+
}
|
74
|
+
RUCY_END
|
75
|
+
|
76
|
+
static
|
77
|
+
RUCY_DEF1(set_min_height, height)
|
78
|
+
{
|
79
|
+
CHECK;
|
80
|
+
THIS->set_min_height(to<int>(height));
|
81
|
+
return value(THIS->min_height());
|
82
|
+
}
|
83
|
+
RUCY_END
|
84
|
+
|
85
|
+
static
|
86
|
+
RUCY_DEF0(min_height)
|
87
|
+
{
|
88
|
+
CHECK;
|
89
|
+
return value(THIS->min_height());
|
90
|
+
}
|
91
|
+
RUCY_END
|
92
|
+
|
93
|
+
static
|
94
|
+
RUCY_DEF1(set_resize, resize)
|
95
|
+
{
|
96
|
+
CHECK;
|
97
|
+
THIS->set_resize(to<bool>(resize));
|
98
|
+
return value(THIS->is_resize());
|
99
|
+
}
|
100
|
+
RUCY_END
|
101
|
+
|
102
|
+
static
|
103
|
+
RUCY_DEF0(is_resize)
|
104
|
+
{
|
105
|
+
CHECK;
|
106
|
+
return value(THIS->is_resize());
|
107
|
+
}
|
108
|
+
RUCY_END
|
109
|
+
|
110
|
+
static
|
111
|
+
RUCY_DEF1(set_crop, crop)
|
112
|
+
{
|
113
|
+
CHECK;
|
114
|
+
THIS->set_crop(to<bool>(crop));
|
115
|
+
return value(THIS->is_crop());
|
116
|
+
}
|
117
|
+
RUCY_END
|
118
|
+
|
119
|
+
static
|
120
|
+
RUCY_DEF0(is_crop)
|
121
|
+
{
|
122
|
+
CHECK;
|
123
|
+
return value(THIS->is_crop());
|
124
|
+
}
|
125
|
+
RUCY_END
|
126
|
+
|
56
127
|
static
|
57
128
|
RUCY_DEF0(image)
|
58
129
|
{
|
@@ -62,6 +133,18 @@ RUCY_DEF0(image)
|
|
62
133
|
}
|
63
134
|
RUCY_END
|
64
135
|
|
136
|
+
static
|
137
|
+
RUCY_DEF0(device_names)
|
138
|
+
{
|
139
|
+
auto names = Rays::get_camera_device_names();
|
140
|
+
|
141
|
+
std::vector<Value> v;
|
142
|
+
for (auto it = names.begin(), end = names.end(); it != end; ++it)
|
143
|
+
v.emplace_back(value(it->c_str()));
|
144
|
+
return value(v.size(), &v[0]);
|
145
|
+
}
|
146
|
+
RUCY_END
|
147
|
+
|
65
148
|
|
66
149
|
static Class cCamera;
|
67
150
|
|
@@ -72,11 +155,20 @@ Init_camera ()
|
|
72
155
|
|
73
156
|
cCamera = mRays.define_class("Camera");
|
74
157
|
cCamera.define_alloc_func(alloc);
|
75
|
-
cCamera.define_private_method("
|
76
|
-
cCamera.define_method("start",
|
77
|
-
cCamera.define_method("stop",
|
158
|
+
cCamera.define_private_method("setup", setup);
|
159
|
+
cCamera.define_method("start", start);
|
160
|
+
cCamera.define_method("stop", stop);
|
78
161
|
cCamera.define_method("active?", is_active);
|
79
|
-
cCamera.define_method("
|
162
|
+
cCamera.define_method("min_width=", set_min_width);
|
163
|
+
cCamera.define_method("min_width", min_width);
|
164
|
+
cCamera.define_method("min_height=", set_min_height);
|
165
|
+
cCamera.define_method("min_height", min_height);
|
166
|
+
cCamera.define_method("resize=", set_resize);
|
167
|
+
cCamera.define_method("resize?", is_resize);
|
168
|
+
cCamera.define_method("crop=", set_crop);
|
169
|
+
cCamera.define_method("crop?", is_crop);
|
170
|
+
cCamera.define_method("image", image);
|
171
|
+
cCamera.define_module_function("device_names", device_names);
|
80
172
|
}
|
81
173
|
|
82
174
|
|
data/include/rays/camera.h
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
#define __RAYS_CAMERA_H__
|
5
5
|
|
6
6
|
|
7
|
+
#include <vector>
|
7
8
|
#include <xot/pimpl.h>
|
8
9
|
#include <rays/defs.h>
|
9
10
|
#include <rays/image.h>
|
@@ -20,7 +21,12 @@ namespace Rays
|
|
20
21
|
|
21
22
|
public:
|
22
23
|
|
23
|
-
Camera (
|
24
|
+
Camera (
|
25
|
+
const char* device_name = NULL,
|
26
|
+
int min_width = -1,
|
27
|
+
int min_height = -1,
|
28
|
+
bool resize = true,
|
29
|
+
bool crop = true);
|
24
30
|
|
25
31
|
~Camera ();
|
26
32
|
|
@@ -30,6 +36,22 @@ namespace Rays
|
|
30
36
|
|
31
37
|
bool is_active () const;
|
32
38
|
|
39
|
+
void set_min_width (int width);
|
40
|
+
|
41
|
+
int min_width () const;
|
42
|
+
|
43
|
+
void set_min_height (int height);
|
44
|
+
|
45
|
+
int min_height () const;
|
46
|
+
|
47
|
+
void set_resize (bool resize = true);
|
48
|
+
|
49
|
+
bool is_resize () const;
|
50
|
+
|
51
|
+
void set_crop (bool crop = true);
|
52
|
+
|
53
|
+
bool is_crop () const;
|
54
|
+
|
33
55
|
const Image* image () const;
|
34
56
|
|
35
57
|
operator bool () const;
|
@@ -43,6 +65,9 @@ namespace Rays
|
|
43
65
|
};// Camera
|
44
66
|
|
45
67
|
|
68
|
+
std::vector<String> get_camera_device_names ();
|
69
|
+
|
70
|
+
|
46
71
|
}// Rays
|
47
72
|
|
48
73
|
|
data/lib/rays/camera.rb
CHANGED
@@ -10,8 +10,11 @@ module Rays
|
|
10
10
|
|
11
11
|
class Camera
|
12
12
|
|
13
|
-
def initialize (
|
14
|
-
|
13
|
+
def initialize (
|
14
|
+
min_width = -1, min_height = -1,
|
15
|
+
device_name: nil, resize: true, crop: true, &block)
|
16
|
+
|
17
|
+
setup device_name, min_width, min_height, resize, crop
|
15
18
|
Xot::BlockUtil.instance_eval_or_block_call self, &block if block
|
16
19
|
end
|
17
20
|
|
data/rays.gemspec
CHANGED
@@ -28,8 +28,8 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.platform = Gem::Platform::RUBY
|
29
29
|
s.required_ruby_version = '~> 2'
|
30
30
|
|
31
|
-
s.add_runtime_dependency 'xot', '~> 0.1'
|
32
|
-
s.add_runtime_dependency 'rucy', '~> 0.1'
|
31
|
+
s.add_runtime_dependency 'xot', '~> 0.1.16'
|
32
|
+
s.add_runtime_dependency 'rucy', '~> 0.1.16'
|
33
33
|
|
34
34
|
s.files = `git ls-files`.split $/
|
35
35
|
s.executables = s.files.grep(%r{^bin/}) {|f| File.basename f}
|
data/src/ios/bitmap.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
// -*- mode: c++ -*-
|
2
2
|
#pragma once
|
3
|
-
#ifndef
|
4
|
-
#define
|
3
|
+
#ifndef __RAYS_SRC_IOS_BITMAP_H__
|
4
|
+
#define __RAYS_SRC_IOS_BITMAP_H__
|
5
5
|
|
6
6
|
|
7
7
|
#import <CoreGraphics/CGImage.h>
|
@@ -12,7 +12,9 @@ namespace Rays
|
|
12
12
|
{
|
13
13
|
|
14
14
|
|
15
|
-
void
|
15
|
+
void Bitmap_draw_image (
|
16
|
+
Bitmap* bitmap, CGImageRef image,
|
17
|
+
coord x = 0, coord y = 0, coord width = -1, coord height = -1);
|
16
18
|
|
17
19
|
|
18
20
|
}// Rays
|
data/src/ios/bitmap.mm
CHANGED
@@ -176,8 +176,12 @@ namespace Rays
|
|
176
176
|
}
|
177
177
|
|
178
178
|
void
|
179
|
-
|
179
|
+
Bitmap_draw_image (
|
180
|
+
Bitmap* bitmap, CGImageRef image,
|
181
|
+
coord x, coord y, coord width, coord height)
|
180
182
|
{
|
183
|
+
if (width == 0 || height == 0) return;
|
184
|
+
|
181
185
|
if (!bitmap || !image)
|
182
186
|
argument_error(__FILE__, __LINE__);
|
183
187
|
|
@@ -185,9 +189,9 @@ namespace Rays
|
|
185
189
|
if (!context)
|
186
190
|
rays_error(__FILE__, __LINE__, "getting CGContext failed.");
|
187
191
|
|
188
|
-
|
189
|
-
|
190
|
-
CGContextDrawImage(context, CGRectMake(
|
192
|
+
if (width < 0) width = (coord) CGImageGetWidth(image);
|
193
|
+
if (height < 0) height = (coord) CGImageGetHeight(image);
|
194
|
+
CGContextDrawImage(context, CGRectMake(x, y, width, height), image);
|
191
195
|
|
192
196
|
Bitmap_set_modified(bitmap);
|
193
197
|
}
|
@@ -265,7 +269,7 @@ namespace Rays
|
|
265
269
|
if (!bmp)
|
266
270
|
rays_error(__FILE__, __LINE__, "invalid bitmap.");
|
267
271
|
|
268
|
-
|
272
|
+
Bitmap_draw_image(&bmp, image);
|
269
273
|
return bmp;
|
270
274
|
}
|
271
275
|
|
data/src/ios/camera.mm
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
|
5
5
|
#import <AVFoundation/AVFoundation.h>
|
6
|
+
#include "rays/exception.h"
|
6
7
|
#include "bitmap.h"
|
7
8
|
|
8
9
|
|
@@ -16,9 +17,10 @@ static int video_input_queue_index = 0;
|
|
16
17
|
@implementation VideoInput
|
17
18
|
|
18
19
|
{
|
19
|
-
AVCaptureSession*
|
20
|
-
dispatch_queue_t
|
21
|
-
CGImageRef
|
20
|
+
AVCaptureSession* session;
|
21
|
+
dispatch_queue_t queue;
|
22
|
+
CGImageRef image;
|
23
|
+
AVCaptureVideoOrientation orientation;
|
22
24
|
}
|
23
25
|
|
24
26
|
- (id) init
|
@@ -26,9 +28,10 @@ static int video_input_queue_index = 0;
|
|
26
28
|
self = [super init];
|
27
29
|
if (self)
|
28
30
|
{
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
session = nil;
|
32
|
+
queue = nil;
|
33
|
+
image = nil;
|
34
|
+
orientation = AVCaptureVideoOrientationPortrait;
|
32
35
|
}
|
33
36
|
return self;
|
34
37
|
}
|
@@ -38,37 +41,38 @@ static int video_input_queue_index = 0;
|
|
38
41
|
[self stop];
|
39
42
|
[self clearImage];
|
40
43
|
|
41
|
-
if (
|
44
|
+
if (queue)
|
42
45
|
{
|
43
|
-
dispatch_release(
|
44
|
-
|
46
|
+
dispatch_release(queue);
|
47
|
+
queue = nil;
|
45
48
|
}
|
46
49
|
|
47
50
|
[super dealloc];
|
48
51
|
}
|
49
52
|
|
50
|
-
- (dispatch_queue_t)
|
53
|
+
- (dispatch_queue_t) getQueue
|
51
54
|
{
|
52
|
-
if (!
|
55
|
+
if (!queue)
|
53
56
|
{
|
54
57
|
auto name = Xot::stringf(
|
55
58
|
"org.xord.RaysVideoInputQueue_%d",
|
56
59
|
video_input_queue_index++);
|
57
|
-
|
60
|
+
queue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL);
|
58
61
|
}
|
59
|
-
return
|
62
|
+
return queue;
|
60
63
|
}
|
61
64
|
|
62
|
-
- (BOOL) start
|
65
|
+
- (BOOL) start: (AVCaptureDevice*) device
|
66
|
+
preset: (AVCaptureSessionPreset) preset
|
63
67
|
{
|
64
|
-
|
68
|
+
if (!device) return NO;
|
65
69
|
|
66
|
-
|
67
|
-
|
70
|
+
[self stop];
|
71
|
+
[self updateOrientation];
|
68
72
|
|
69
|
-
|
70
|
-
|
71
|
-
|
73
|
+
AVCaptureSession* sess = [[[AVCaptureSession alloc] init] autorelease];
|
74
|
+
if (preset != nil)
|
75
|
+
sess.sessionPreset = preset;
|
72
76
|
|
73
77
|
//device.activeVideoMinFrameDuration = CMTimeMake(1, 30);
|
74
78
|
|
@@ -76,7 +80,7 @@ static int video_input_queue_index = 0;
|
|
76
80
|
AVCaptureDeviceInput* input = [[[AVCaptureDeviceInput alloc]
|
77
81
|
initWithDevice: device error: &error]
|
78
82
|
autorelease];
|
79
|
-
if (!input || error || ![
|
83
|
+
if (!input || error || ![sess canAddInput: input])
|
80
84
|
return NO;
|
81
85
|
|
82
86
|
AVCaptureVideoDataOutput* output =
|
@@ -85,22 +89,63 @@ static int video_input_queue_index = 0;
|
|
85
89
|
(NSString*) kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)
|
86
90
|
};
|
87
91
|
output.alwaysDiscardsLateVideoFrames = YES;
|
88
|
-
[output setSampleBufferDelegate: self queue: self
|
89
|
-
if (![
|
92
|
+
[output setSampleBufferDelegate: self queue: [self getQueue]];
|
93
|
+
if (![sess canAddOutput: output])
|
90
94
|
return NO;
|
91
95
|
|
92
|
-
[
|
93
|
-
[
|
94
|
-
|
96
|
+
[sess addInput: input];
|
97
|
+
[sess addOutput: output];
|
98
|
+
|
99
|
+
AVCaptureConnection* connection =
|
100
|
+
[output connectionWithMediaType: AVMediaTypeVideo];
|
101
|
+
if (connection)
|
102
|
+
{
|
103
|
+
if (connection.isVideoOrientationSupported)
|
104
|
+
[connection setVideoOrientation: orientation];
|
95
105
|
|
96
|
-
|
106
|
+
if (connection.isVideoMirroringSupported)
|
107
|
+
{
|
108
|
+
[connection setVideoMirrored:
|
109
|
+
device.position == AVCaptureDevicePositionFront];
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
[sess startRunning];
|
114
|
+
|
115
|
+
session = [sess retain];
|
97
116
|
return YES;
|
98
117
|
}
|
99
118
|
|
119
|
+
- (void) updateCaptureOrientation
|
120
|
+
{
|
121
|
+
assert(Thread.isMainThread);
|
122
|
+
|
123
|
+
switch (UIApplication.sharedApplication.statusBarOrientation)
|
124
|
+
{
|
125
|
+
case UIInterfaceOrientationPortraitUpsideDown:
|
126
|
+
orientation = AVCaptureVideoOrientationPortraitUpsideDown;
|
127
|
+
break;
|
128
|
+
|
129
|
+
case UIInterfaceOrientationPortraitLandscapeLeft:
|
130
|
+
orientation = AVCaptureVideoOrientationLandscapeLeft;
|
131
|
+
break;
|
132
|
+
|
133
|
+
case UIInterfaceOrientationPortraitLandscapeRight:
|
134
|
+
orientation = AVCaptureVideoOrientationLandscapeRight;
|
135
|
+
break;
|
136
|
+
|
137
|
+
default:
|
138
|
+
orientation = AVCaptureVideoOrientationPortrait;
|
139
|
+
break;
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
100
143
|
- (void) captureOutput: (AVCaptureOutput*) output
|
101
144
|
didOutputSampleBuffer: (CMSampleBufferRef) sampleBuffer
|
102
145
|
fromConnection: (AVCaptureConnection*) connection
|
103
146
|
{
|
147
|
+
[connection setVideoOrientation: orientation];
|
148
|
+
|
104
149
|
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
105
150
|
if (!pixelBuffer) return;
|
106
151
|
|
@@ -115,35 +160,37 @@ static int video_input_queue_index = 0;
|
|
115
160
|
|
116
161
|
dispatch_async(dispatch_get_main_queue(), ^{
|
117
162
|
[self clearImage];
|
118
|
-
|
163
|
+
image = cgImage;
|
164
|
+
|
165
|
+
[self updateOrientation];
|
119
166
|
});
|
120
167
|
}
|
121
168
|
|
122
169
|
- (void) stop
|
123
170
|
{
|
124
|
-
if (!
|
171
|
+
if (!session) return;
|
125
172
|
|
126
|
-
[
|
127
|
-
[
|
128
|
-
|
173
|
+
[session stopRunning];
|
174
|
+
[session release];
|
175
|
+
session = nil;
|
129
176
|
}
|
130
177
|
|
131
178
|
- (BOOL) isActive
|
132
179
|
{
|
133
|
-
return
|
180
|
+
return session != nil;
|
134
181
|
}
|
135
182
|
|
136
183
|
- (void) clearImage
|
137
184
|
{
|
138
|
-
if (!
|
185
|
+
if (!image) return;
|
139
186
|
|
140
|
-
CGImageRelease(
|
141
|
-
|
187
|
+
CGImageRelease(image);
|
188
|
+
image = nil;
|
142
189
|
}
|
143
190
|
|
144
191
|
- (CGImageRef) getImage
|
145
192
|
{
|
146
|
-
return
|
193
|
+
return image;
|
147
194
|
}
|
148
195
|
|
149
196
|
@end// VideoInput
|
@@ -156,10 +203,51 @@ namespace Rays
|
|
156
203
|
struct Camera::Data
|
157
204
|
{
|
158
205
|
|
206
|
+
String device_name;
|
207
|
+
|
208
|
+
int min_width = -1, min_height = -1;
|
209
|
+
|
210
|
+
bool resize = false, crop = false;
|
211
|
+
|
159
212
|
mutable Image image;
|
160
213
|
|
161
214
|
VideoInput* video_input = nil;
|
162
215
|
|
216
|
+
AVCaptureSessionPreset get_preset (AVCaptureDevice* device)
|
217
|
+
{
|
218
|
+
int w = min_width, h = min_height;
|
219
|
+
if (w > 0 && h > 0)
|
220
|
+
{
|
221
|
+
#define SUPPORT(x) \
|
222
|
+
[device supportsAVCaptureSessionPreset: AVCaptureSessionPreset##x]
|
223
|
+
|
224
|
+
//if (w <= 320 && h <= 240 && SUPPORT(320x240))
|
225
|
+
// return AVCaptureSessionPreset320x240;
|
226
|
+
|
227
|
+
if (w <= 352 && h <= 288 && SUPPORT(352x288))
|
228
|
+
return AVCaptureSessionPreset352x288;
|
229
|
+
|
230
|
+
if (w <= 640 && h <= 480 && SUPPORT(640x480))
|
231
|
+
return AVCaptureSessionPreset640x480;
|
232
|
+
|
233
|
+
//if (w <= 960 && h <= 540 && SUPPORT(960x540))
|
234
|
+
// return AVCaptureSessionPreset960x540;
|
235
|
+
|
236
|
+
if (w <= 1280 && h <= 720 && SUPPORT(1280x720))
|
237
|
+
return AVCaptureSessionPreset1280x720;
|
238
|
+
|
239
|
+
if (/*w <= 1920 && h <= 1080 &&*/ SUPPORT(1920x1080))
|
240
|
+
return AVCaptureSessionPreset1920x1080;
|
241
|
+
|
242
|
+
//if (SUPPORT(3840x2160))
|
243
|
+
// return AVCaptureSessionPreset3840x2160;
|
244
|
+
|
245
|
+
#undef SUPPORT
|
246
|
+
}
|
247
|
+
|
248
|
+
return nil;
|
249
|
+
}
|
250
|
+
|
163
251
|
void update_image_from_video_input () const
|
164
252
|
{
|
165
253
|
if (!video_input) return;
|
@@ -167,24 +255,160 @@ namespace Rays
|
|
167
255
|
CGImageRef cgImage = [video_input getImage];
|
168
256
|
if (!cgImage) return;
|
169
257
|
|
170
|
-
|
258
|
+
coord draw_x, draw_y, draw_width, draw_height;
|
259
|
+
int bitmap_width, bitmap_height;
|
260
|
+
get_draw_bounds(
|
261
|
+
&draw_x, &draw_y, &draw_width, &draw_height,
|
262
|
+
&bitmap_width, &bitmap_height,
|
263
|
+
cgImage);
|
264
|
+
|
265
|
+
if (
|
266
|
+
!image ||
|
267
|
+
image.bitmap().width() != bitmap_width ||
|
268
|
+
image.bitmap().height() != bitmap_height)
|
171
269
|
{
|
172
|
-
Bitmap
|
173
|
-
(int) CGImageGetWidth(cgImage),
|
174
|
-
(int) CGImageGetHeight(cgImage));
|
175
|
-
image = Image(bmp);
|
270
|
+
image = Image(Bitmap(bitmap_width, bitmap_height));
|
176
271
|
}
|
177
272
|
|
178
|
-
|
273
|
+
Bitmap_draw_image(
|
274
|
+
&image.bitmap(), cgImage,
|
275
|
+
draw_x, draw_y, draw_width, draw_height);
|
179
276
|
|
180
277
|
[video_input clearImage];
|
181
278
|
}
|
182
279
|
|
280
|
+
void get_draw_bounds (
|
281
|
+
coord* draw_x, coord* draw_y, coord* draw_width, coord* draw_height,
|
282
|
+
int* bitmap_width, int* bitmap_height,
|
283
|
+
CGImageRef image) const
|
284
|
+
{
|
285
|
+
int image_width = (int) CGImageGetWidth(image);
|
286
|
+
int image_height = (int) CGImageGetHeight(image);
|
287
|
+
float image_ratio = (float) image_width / (float) image_height;
|
288
|
+
|
289
|
+
if (resize && min_width > 0 && min_height > 0)
|
290
|
+
{
|
291
|
+
float min_size_ratio = (float) min_width / (float) min_height;
|
292
|
+
if (image_ratio > min_size_ratio)
|
293
|
+
{
|
294
|
+
*draw_width = min_height * image_ratio;
|
295
|
+
*draw_height = min_height;
|
296
|
+
}
|
297
|
+
else
|
298
|
+
{
|
299
|
+
*draw_width = min_width;
|
300
|
+
*draw_height = min_width / image_ratio;
|
301
|
+
}
|
302
|
+
}
|
303
|
+
else if (resize && min_width > 0)
|
304
|
+
{
|
305
|
+
*draw_width = min_width;
|
306
|
+
*draw_height = min_width / image_ratio;
|
307
|
+
}
|
308
|
+
else if (resize && min_height > 0)
|
309
|
+
{
|
310
|
+
*draw_width = min_height * image_ratio;
|
311
|
+
*draw_height = min_height;
|
312
|
+
}
|
313
|
+
else
|
314
|
+
{
|
315
|
+
*draw_width = image_width;
|
316
|
+
*draw_height = image_height;
|
317
|
+
}
|
318
|
+
|
319
|
+
*draw_x = 0;
|
320
|
+
*draw_y = 0;
|
321
|
+
*bitmap_width = *draw_width;
|
322
|
+
*bitmap_height = *draw_height;
|
323
|
+
|
324
|
+
if (crop && min_width > 0)
|
325
|
+
{
|
326
|
+
*draw_x = min_width / 2 - *draw_width / 2;
|
327
|
+
*bitmap_width = min_width;
|
328
|
+
}
|
329
|
+
else if (crop && min_height > 0)
|
330
|
+
{
|
331
|
+
*draw_y = min_height / 2 - *draw_height / 2;
|
332
|
+
*bitmap_height = min_height;
|
333
|
+
}
|
334
|
+
}
|
335
|
+
|
183
336
|
};// Camera::Data
|
184
337
|
|
185
338
|
|
186
|
-
|
339
|
+
static NSArray<AVCaptureDevice*>*
|
340
|
+
get_video_devices ()
|
187
341
|
{
|
342
|
+
#if 0
|
343
|
+
AVCaptureDeviceDiscoverySession* discoverySession =
|
344
|
+
[AVCaptureDeviceDiscoverySession
|
345
|
+
discoverySessionWithDeviceTypes: @[
|
346
|
+
AVCaptureDeviceTypeBuiltInWideAngleCamera]
|
347
|
+
mediaType: AVMediaTypeVideo
|
348
|
+
position: AVCaptureDevicePositionUnspecified];
|
349
|
+
NSArray<AVCaptureDevice*>* devices = discoverySession.devices;
|
350
|
+
for (AVCaptureDevice* d in devices)
|
351
|
+
{
|
352
|
+
printf("%s\n", d.localizedName.UTF8String);
|
353
|
+
}
|
354
|
+
#endif
|
355
|
+
NSMutableArray<AVCaptureDevice*>* devices = [NSMutableArray array];
|
356
|
+
for (AVCaptureDevice* d in AVCaptureDevice.devices)
|
357
|
+
{
|
358
|
+
if ([d hasMediaType: AVMediaTypeVideo])
|
359
|
+
[devices addObject: d];
|
360
|
+
}
|
361
|
+
return devices;
|
362
|
+
}
|
363
|
+
|
364
|
+
static AVCaptureDevice*
|
365
|
+
get_default_video_device ()
|
366
|
+
{
|
367
|
+
AVCaptureDevice* device =
|
368
|
+
[AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
|
369
|
+
if (!device)
|
370
|
+
rays_error(__FILE__, __LINE__, "Default camera device is not found.");
|
371
|
+
|
372
|
+
return device;
|
373
|
+
}
|
374
|
+
|
375
|
+
static AVCaptureDevice*
|
376
|
+
get_video_device (const char* name)
|
377
|
+
{
|
378
|
+
if (!name || *name == 0)
|
379
|
+
return get_default_video_device();
|
380
|
+
|
381
|
+
for (AVCaptureDevice* d in get_video_devices())
|
382
|
+
{
|
383
|
+
if (strcmp(name, d.localizedName.UTF8String) == 0)
|
384
|
+
return d;
|
385
|
+
}
|
386
|
+
|
387
|
+
rays_error(__FILE__, __LINE__, "Camera device '%s' is not found.", name);
|
388
|
+
return nil;
|
389
|
+
}
|
390
|
+
|
391
|
+
std::vector<String>
|
392
|
+
get_camera_device_names ()
|
393
|
+
{
|
394
|
+
std::vector<String> names;
|
395
|
+
for (AVCaptureDevice* d in get_video_devices())
|
396
|
+
names.emplace_back(d.localizedName.UTF8String);
|
397
|
+
return names;
|
398
|
+
}
|
399
|
+
|
400
|
+
|
401
|
+
Camera::Camera (
|
402
|
+
const char* device_name,
|
403
|
+
int min_width, int min_height, bool resize, bool crop)
|
404
|
+
{
|
405
|
+
if (device_name)
|
406
|
+
self->device_name = device_name;
|
407
|
+
|
408
|
+
self->min_width = min_width;
|
409
|
+
self->min_height = min_height;
|
410
|
+
self->resize = resize;
|
411
|
+
self->crop = crop;
|
188
412
|
}
|
189
413
|
|
190
414
|
Camera::~Camera ()
|
@@ -197,7 +421,9 @@ namespace Rays
|
|
197
421
|
Camera::start ()
|
198
422
|
{
|
199
423
|
if (!self->video_input) self->video_input = [[VideoInput alloc] init];
|
200
|
-
|
424
|
+
|
425
|
+
AVCaptureDevice* device = get_video_device(self->device_name.c_str());
|
426
|
+
return [self->video_input start: device preset: self->get_preset(device)];
|
201
427
|
}
|
202
428
|
|
203
429
|
void
|
@@ -214,6 +440,54 @@ namespace Rays
|
|
214
440
|
return self->video_input && [self->video_input isActive];
|
215
441
|
}
|
216
442
|
|
443
|
+
void
|
444
|
+
Camera::set_min_width (int width)
|
445
|
+
{
|
446
|
+
self->min_width = width;
|
447
|
+
}
|
448
|
+
|
449
|
+
int
|
450
|
+
Camera::min_width () const
|
451
|
+
{
|
452
|
+
return self->min_width;
|
453
|
+
}
|
454
|
+
|
455
|
+
void
|
456
|
+
Camera::set_min_height (int height)
|
457
|
+
{
|
458
|
+
self->min_height = height;
|
459
|
+
}
|
460
|
+
|
461
|
+
int
|
462
|
+
Camera::min_height () const
|
463
|
+
{
|
464
|
+
return self->min_height;
|
465
|
+
}
|
466
|
+
|
467
|
+
void
|
468
|
+
Camera::set_resize (bool resize)
|
469
|
+
{
|
470
|
+
self->resize = resize;
|
471
|
+
}
|
472
|
+
|
473
|
+
bool
|
474
|
+
Camera::is_resize () const
|
475
|
+
{
|
476
|
+
return self->resize;
|
477
|
+
}
|
478
|
+
|
479
|
+
void
|
480
|
+
Camera::set_crop (bool crop)
|
481
|
+
{
|
482
|
+
self->crop = crop;
|
483
|
+
}
|
484
|
+
|
485
|
+
bool
|
486
|
+
Camera::is_crop () const
|
487
|
+
{
|
488
|
+
return self->crop;
|
489
|
+
}
|
490
|
+
|
217
491
|
const Image*
|
218
492
|
Camera::image () const
|
219
493
|
{
|