rays 0.1.14 → 0.1.19

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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/rays/camera.cpp +171 -0
  3. data/.doc/ext/rays/color.cpp +2 -3
  4. data/.doc/ext/rays/color_space.cpp +22 -14
  5. data/.doc/ext/rays/font.cpp +30 -0
  6. data/.doc/ext/rays/image.cpp +1 -1
  7. data/.doc/ext/rays/native.cpp +4 -4
  8. data/.doc/ext/rays/painter.cpp +83 -0
  9. data/.doc/ext/rays/point.cpp +14 -0
  10. data/.doc/ext/rays/polygon.cpp +33 -7
  11. data/.doc/ext/rays/polyline.cpp +12 -6
  12. data/.doc/ext/rays/rays.cpp +105 -1
  13. data/Rakefile +3 -0
  14. data/VERSION +1 -1
  15. data/ext/rays/bitmap.cpp +1 -1
  16. data/ext/rays/camera.cpp +186 -0
  17. data/ext/rays/color.cpp +2 -3
  18. data/ext/rays/color_space.cpp +22 -14
  19. data/ext/rays/extconf.rb +1 -1
  20. data/ext/rays/font.cpp +35 -2
  21. data/ext/rays/image.cpp +2 -2
  22. data/ext/rays/native.cpp +4 -4
  23. data/ext/rays/painter.cpp +94 -3
  24. data/ext/rays/point.cpp +16 -0
  25. data/ext/rays/polygon.cpp +34 -6
  26. data/ext/rays/polyline.cpp +11 -5
  27. data/ext/rays/rays.cpp +105 -1
  28. data/include/rays/camera.h +74 -0
  29. data/include/rays/color_space.h +4 -2
  30. data/include/rays/defs.h +33 -0
  31. data/include/rays/exception.h +6 -2
  32. data/include/rays/image.h +1 -1
  33. data/include/rays/painter.h +38 -0
  34. data/include/rays/polygon.h +35 -1
  35. data/include/rays/polyline.h +7 -1
  36. data/include/rays/ruby/camera.h +41 -0
  37. data/include/rays/ruby/rays.h +8 -0
  38. data/lib/rays.rb +2 -2
  39. data/lib/rays/camera.rb +24 -0
  40. data/lib/rays/image.rb +1 -1
  41. data/lib/rays/painter.rb +23 -1
  42. data/lib/rays/polygon.rb +8 -0
  43. data/rays.gemspec +2 -2
  44. data/src/color_space.cpp +2 -2
  45. data/src/image.cpp +1 -1
  46. data/src/ios/bitmap.h +23 -0
  47. data/src/ios/bitmap.mm +32 -11
  48. data/src/ios/camera.mm +517 -0
  49. data/src/ios/font.mm +2 -2
  50. data/src/ios/helper.h +2 -2
  51. data/src/osx/bitmap.h +23 -0
  52. data/src/osx/bitmap.mm +28 -10
  53. data/src/osx/camera.mm +452 -0
  54. data/src/osx/font.mm +2 -2
  55. data/src/painter.cpp +100 -10
  56. data/src/polygon.cpp +203 -37
  57. data/src/polyline.cpp +4 -2
  58. data/src/polyline.h +3 -1
  59. data/test/test_font.rb +5 -0
  60. data/test/test_painter.rb +65 -5
  61. data/test/test_painter_shape.rb +48 -3
  62. data/test/test_point.rb +8 -0
  63. data/test/test_polyline.rb +26 -0
  64. metadata +19 -9
@@ -4,7 +4,10 @@
4
4
  #define __RAYS_RUBY_RAYS_H__
5
5
 
6
6
 
7
+ #include <rucy/rucy.h>
7
8
  #include <rucy/module.h>
9
+ #include <rucy/extension.h>
10
+ #include <rays/rays.h>
8
11
 
9
12
 
10
13
  namespace Rays
@@ -18,4 +21,9 @@ namespace Rays
18
21
  }// Rays
19
22
 
20
23
 
24
+ RUCY_DECLARE_CONVERT_TO(Rays::CapType)
25
+
26
+ RUCY_DECLARE_CONVERT_TO(Rays::JoinType)
27
+
28
+
21
29
  #endif//EOH
@@ -10,6 +10,7 @@ require 'rays/color'
10
10
  require 'rays/color_space'
11
11
  require 'rays/matrix'
12
12
 
13
+ require 'rays/painter'
13
14
  require 'rays/polyline'
14
15
  require 'rays/polygon'
15
16
  require 'rays/polygon_line'
@@ -17,5 +18,4 @@ require 'rays/bitmap'
17
18
  require 'rays/image'
18
19
  require 'rays/font'
19
20
  require 'rays/shader'
20
-
21
- require 'rays/painter'
21
+ require 'rays/camera'
@@ -0,0 +1,24 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+
4
+ require 'xot/block_util'
5
+ require 'rays/ext'
6
+
7
+
8
+ module Rays
9
+
10
+
11
+ class Camera
12
+
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
18
+ Xot::BlockUtil.instance_eval_or_block_call self, &block if block
19
+ end
20
+
21
+ end# Camera
22
+
23
+
24
+ end# Rays
@@ -24,7 +24,7 @@ module Rays
24
24
  end
25
25
 
26
26
  def bounds ()
27
- Bounds.new 0, 0, *size
27
+ Bounds.new 0, 0, width, height
28
28
  end
29
29
 
30
30
  end# Image
@@ -1,6 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
 
4
+ require 'xot/const_symbol_accessor'
4
5
  require 'xot/universal_accessor'
5
6
  require 'xot/block_util'
6
7
  require 'rays/ext'
@@ -73,6 +74,14 @@ module Rays
73
74
  draw_ellipse args, center, radius, hole, from, to
74
75
  end
75
76
 
77
+ def curve (*args, loop: false)
78
+ draw_curve args, loop
79
+ end
80
+
81
+ def bezier (*args, loop: false)
82
+ draw_bezier args, loop
83
+ end
84
+
76
85
  def color= (fill, stroke = nil)
77
86
  self.fill fill
78
87
  self.stroke stroke
@@ -87,8 +96,21 @@ module Rays
87
96
  set_shader shader
88
97
  end
89
98
 
99
+ const_symbol_accessor :stroke_cap, {
100
+ butt: CAP_BUTT,
101
+ round: CAP_ROUND,
102
+ square: CAP_SQUARE
103
+ }
104
+
105
+ const_symbol_accessor :stroke_join, {
106
+ miter: JOIN_MITER,
107
+ round: JOIN_ROUND,
108
+ square: JOIN_SQUARE
109
+ }
110
+
90
111
  universal_accessor :background, :fill, :stroke, :color,
91
- :stroke_width, :nsegment, :shader, :clip, :font
112
+ :stroke_width, :stroke_cap, :stroke_join, :miter_limit,
113
+ :nsegment, :shader, :clip, :font
92
114
 
93
115
  private
94
116
 
@@ -44,6 +44,14 @@ module Rays
44
44
  create_ellipse args, center, radius, hole, from, to, nsegment
45
45
  end
46
46
 
47
+ def self.curve (*args, loop: false)
48
+ create_curve args, loop
49
+ end
50
+
51
+ def self.bezier (*args, loop: false)
52
+ create_bezier args, loop
53
+ end
54
+
47
55
  end# Polygon
48
56
 
49
57
 
@@ -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.19'
32
+ s.add_runtime_dependency 'rucy', '~> 0.1.18'
33
33
 
34
34
  s.files = `git ls-files`.split $/
35
35
  s.executables = s.files.grep(%r{^bin/}) {|f| File.basename f}
@@ -55,7 +55,7 @@ namespace Rays
55
55
  32, 32, 32, // RGB(A) float
56
56
  32, 32, 32, // BGR(A) float
57
57
  };
58
- if (type_ < 0 || COLORSPACE_LAST <= type_) return BPPS[COLORSPACE_UNKNOWN];
58
+ if (type_ < 0 || COLORSPACE_MAX <= type_) return BPPS[COLORSPACE_UNKNOWN];
59
59
  return BPPS[type_];
60
60
  }
61
61
 
@@ -78,7 +78,7 @@ namespace Rays
78
78
  96, 128, 128, // RGB(A) float
79
79
  96, 128, 128, // BGR(A) float
80
80
  };
81
- if (type_ < 0 || COLORSPACE_LAST <= type_) return BPPS[COLORSPACE_UNKNOWN];
81
+ if (type_ < 0 || COLORSPACE_MAX <= type_) return BPPS[COLORSPACE_UNKNOWN];
82
82
  return BPPS[type_];
83
83
  }
84
84
 
@@ -1,4 +1,4 @@
1
- #include "rays/image.h"
1
+ #include "image.h"
2
2
 
3
3
 
4
4
  #include <math.h>
@@ -0,0 +1,23 @@
1
+ // -*- mode: c++ -*-
2
+ #pragma once
3
+ #ifndef __RAYS_SRC_IOS_BITMAP_H__
4
+ #define __RAYS_SRC_IOS_BITMAP_H__
5
+
6
+
7
+ #import <CoreGraphics/CGImage.h>
8
+ #include "../bitmap.h"
9
+
10
+
11
+ namespace Rays
12
+ {
13
+
14
+
15
+ void Bitmap_draw_image (
16
+ Bitmap* bitmap, CGImageRef image,
17
+ coord x = 0, coord y = 0, coord width = -1, coord height = -1);
18
+
19
+
20
+ }// Rays
21
+
22
+
23
+ #endif//EOH
@@ -1,5 +1,5 @@
1
1
  // -*- objc -*-
2
- #import "../bitmap.h"
2
+ #import "bitmap.h"
3
3
 
4
4
 
5
5
  #import <ImageIO/CGImageDestination.h>
@@ -27,14 +27,14 @@ namespace Rays
27
27
  if (cs.is_alpha_first())
28
28
  {
29
29
  info |= cs.is_premult()
30
- ? kCGImageAlphaPremultipliedFirst
31
- : kCGImageAlphaFirst;
30
+ ? kCGImageAlphaPremultipliedFirst
31
+ : kCGImageAlphaFirst;
32
32
  }
33
33
  else if (cs.is_alpha_last())
34
34
  {
35
35
  info |= cs.is_premult()
36
- ? kCGImageAlphaPremultipliedLast
37
- : kCGImageAlphaLast;
36
+ ? kCGImageAlphaPremultipliedLast
37
+ : kCGImageAlphaLast;
38
38
  }
39
39
  else if (cs.is_skip_first())
40
40
  info |= kCGImageAlphaNoneSkipFirst;
@@ -175,6 +175,27 @@ namespace Rays
175
175
  return bmp;
176
176
  }
177
177
 
178
+ void
179
+ Bitmap_draw_image (
180
+ Bitmap* bitmap, CGImageRef image,
181
+ coord x, coord y, coord width, coord height)
182
+ {
183
+ if (width == 0 || height == 0) return;
184
+
185
+ if (!bitmap || !image)
186
+ argument_error(__FILE__, __LINE__);
187
+
188
+ CGContextRef context = bitmap->self->get_context();
189
+ if (!context)
190
+ rays_error(__FILE__, __LINE__, "getting CGContext failed.");
191
+
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);
195
+
196
+ Bitmap_set_modified(bitmap);
197
+ }
198
+
178
199
  void
179
200
  Bitmap_draw_string (
180
201
  Bitmap* bitmap, const RawFont& font, const char* str, coord x, coord y)
@@ -185,6 +206,7 @@ namespace Rays
185
206
  if (*str == '\0') return;
186
207
 
187
208
  font.draw_string(bitmap->self->get_context(), bitmap->height(), str, x, y);
209
+
188
210
  Bitmap_set_modified(bitmap);
189
211
  }
190
212
 
@@ -247,11 +269,7 @@ namespace Rays
247
269
  if (!bmp)
248
270
  rays_error(__FILE__, __LINE__, "invalid bitmap.");
249
271
 
250
- CGContextRef context = bmp.self->get_context();
251
- if (!context)
252
- rays_error(__FILE__, __LINE__, "creating CGContext failed.");
253
-
254
- CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
272
+ Bitmap_draw_image(&bmp, image);
255
273
  return bmp;
256
274
  }
257
275
 
@@ -329,7 +347,10 @@ namespace Rays
329
347
  Bitmap::operator bool () const
330
348
  {
331
349
  return
332
- self->width > 0 && self->height > 0 && self->color_space && self->pixels;
350
+ self->width > 0 &&
351
+ self->height > 0 &&
352
+ self->color_space &&
353
+ self->pixels;
333
354
  }
334
355
 
335
356
  bool
@@ -0,0 +1,517 @@
1
+ // -*- mode: objc -*-
2
+ #import "rays/camera.h"
3
+
4
+
5
+ #import <AVFoundation/AVFoundation.h>
6
+ #include "rays/exception.h"
7
+ #include "bitmap.h"
8
+
9
+
10
+ static int video_input_queue_index = 0;
11
+
12
+
13
+ @interface VideoInput : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
14
+ @end
15
+
16
+
17
+ @implementation VideoInput
18
+
19
+ {
20
+ AVCaptureSession* session;
21
+ dispatch_queue_t queue;
22
+ CGImageRef image;
23
+ AVCaptureVideoOrientation orientation;
24
+ }
25
+
26
+ - (id) init
27
+ {
28
+ self = [super init];
29
+ if (self)
30
+ {
31
+ session = nil;
32
+ queue = nil;
33
+ image = nil;
34
+ orientation = AVCaptureVideoOrientationPortrait;
35
+ }
36
+ return self;
37
+ }
38
+
39
+ - (void) dealloc
40
+ {
41
+ [self stop];
42
+ [self clearImage];
43
+
44
+ if (queue)
45
+ {
46
+ dispatch_release(queue);
47
+ queue = nil;
48
+ }
49
+
50
+ [super dealloc];
51
+ }
52
+
53
+ - (dispatch_queue_t) getQueue
54
+ {
55
+ if (!queue)
56
+ {
57
+ auto name = Xot::stringf(
58
+ "org.xord.RaysVideoInputQueue_%d",
59
+ video_input_queue_index++);
60
+ queue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL);
61
+ }
62
+ return queue;
63
+ }
64
+
65
+ - (BOOL) start: (AVCaptureDevice*) device
66
+ preset: (AVCaptureSessionPreset) preset
67
+ {
68
+ if (!device) return NO;
69
+
70
+ [self stop];
71
+ [self updateOrientation];
72
+
73
+ AVCaptureSession* sess = [[[AVCaptureSession alloc] init] autorelease];
74
+ if (preset != nil)
75
+ sess.sessionPreset = preset;
76
+
77
+ //device.activeVideoMinFrameDuration = CMTimeMake(1, 30);
78
+
79
+ NSError* error = nil;
80
+ AVCaptureDeviceInput* input = [[[AVCaptureDeviceInput alloc]
81
+ initWithDevice: device error: &error]
82
+ autorelease];
83
+ if (!input || error || ![sess canAddInput: input])
84
+ return NO;
85
+
86
+ AVCaptureVideoDataOutput* output =
87
+ [[[AVCaptureVideoDataOutput alloc] init] autorelease];
88
+ output.videoSettings = @{
89
+ (NSString*) kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)
90
+ };
91
+ output.alwaysDiscardsLateVideoFrames = YES;
92
+ [output setSampleBufferDelegate: self queue: [self getQueue]];
93
+ if (![sess canAddOutput: output])
94
+ return NO;
95
+
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];
105
+
106
+ if (connection.isVideoMirroringSupported)
107
+ {
108
+ [connection setVideoMirrored:
109
+ device.position == AVCaptureDevicePositionFront];
110
+ }
111
+ }
112
+
113
+ [sess startRunning];
114
+
115
+ session = [sess retain];
116
+ return YES;
117
+ }
118
+
119
+ - (void) updateOrientation
120
+ {
121
+ assert(NSThread.isMainThread);
122
+
123
+ switch (UIApplication.sharedApplication.statusBarOrientation)
124
+ {
125
+ case UIInterfaceOrientationPortraitUpsideDown:
126
+ orientation = AVCaptureVideoOrientationPortraitUpsideDown;
127
+ break;
128
+
129
+ case UIInterfaceOrientationLandscapeLeft:
130
+ orientation = AVCaptureVideoOrientationLandscapeLeft;
131
+ break;
132
+
133
+ case UIInterfaceOrientationLandscapeRight:
134
+ orientation = AVCaptureVideoOrientationLandscapeRight;
135
+ break;
136
+
137
+ default:
138
+ orientation = AVCaptureVideoOrientationPortrait;
139
+ break;
140
+ }
141
+ }
142
+
143
+ - (void) captureOutput: (AVCaptureOutput*) output
144
+ didOutputSampleBuffer: (CMSampleBufferRef) sampleBuffer
145
+ fromConnection: (AVCaptureConnection*) connection
146
+ {
147
+ [connection setVideoOrientation: orientation];
148
+
149
+ CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
150
+ if (!pixelBuffer) return;
151
+
152
+ CIImage* ciImage = [CIImage imageWithCVPixelBuffer: pixelBuffer];
153
+ if (!ciImage) return;
154
+
155
+ CIContext* context = [CIContext contextWithOptions: nil];
156
+ size_t width = CVPixelBufferGetWidth(pixelBuffer);
157
+ size_t height = CVPixelBufferGetHeight(pixelBuffer);
158
+ CGRect rect = CGRectMake(0, 0, width, height);
159
+ CGImageRef cgImage = [context createCGImage: ciImage fromRect: rect];
160
+
161
+ dispatch_async(dispatch_get_main_queue(), ^{
162
+ [self clearImage];
163
+ image = cgImage;
164
+
165
+ [self updateOrientation];
166
+ });
167
+ }
168
+
169
+ - (void) stop
170
+ {
171
+ if (!session) return;
172
+
173
+ [session stopRunning];
174
+ [session release];
175
+ session = nil;
176
+ }
177
+
178
+ - (BOOL) isActive
179
+ {
180
+ return session != nil;
181
+ }
182
+
183
+ - (void) clearImage
184
+ {
185
+ if (!image) return;
186
+
187
+ CGImageRelease(image);
188
+ image = nil;
189
+ }
190
+
191
+ - (CGImageRef) getImage
192
+ {
193
+ return image;
194
+ }
195
+
196
+ @end// VideoInput
197
+
198
+
199
+ namespace Rays
200
+ {
201
+
202
+
203
+ struct Camera::Data
204
+ {
205
+
206
+ String device_name;
207
+
208
+ int min_width = -1, min_height = -1;
209
+
210
+ bool resize = false, crop = false;
211
+
212
+ mutable Image image;
213
+
214
+ VideoInput* video_input = nil;
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
+
251
+ void update_image_from_video_input () const
252
+ {
253
+ if (!video_input) return;
254
+
255
+ CGImageRef cgImage = [video_input getImage];
256
+ if (!cgImage) return;
257
+
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)
269
+ {
270
+ image = Image(Bitmap(bitmap_width, bitmap_height));
271
+ }
272
+
273
+ Bitmap_draw_image(
274
+ &image.bitmap(), cgImage,
275
+ draw_x, draw_y, draw_width, draw_height);
276
+
277
+ [video_input clearImage];
278
+ }
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
+ if (crop && min_height > 0)
330
+ {
331
+ *draw_y = min_height / 2 - *draw_height / 2;
332
+ *bitmap_height = min_height;
333
+ }
334
+ }
335
+
336
+ };// Camera::Data
337
+
338
+
339
+ static NSArray<AVCaptureDevice*>*
340
+ get_video_devices ()
341
+ {
342
+ #if 0
343
+ AVCaptureDeviceDiscoverySession* discoverySession =
344
+ [AVCaptureDeviceDiscoverySession
345
+ discoverySessionWithDeviceTypes: @[
346
+ AVCaptureDeviceTypeBuiltInTripleCamera,
347
+ AVCaptureDeviceTypeBuiltInDualWideCamera,
348
+ AVCaptureDeviceTypeBuiltInDualCamera,
349
+ AVCaptureDeviceTypeBuiltInUltraWideCamera,
350
+ AVCaptureDeviceTypeBuiltInTelephotoCamera,
351
+ AVCaptureDeviceTypeBuiltInWideAngleCamera
352
+ ]
353
+ mediaType: AVMediaTypeVideo
354
+ position: AVCaptureDevicePositionUnspecified];
355
+ NSArray<AVCaptureDevice*>* devices = discoverySession.devices;
356
+ for (AVCaptureDevice* d in devices)
357
+ {
358
+ printf("%s\n", d.localizedName.UTF8String);
359
+ }
360
+ #endif
361
+ NSMutableArray<AVCaptureDevice*>* devices = [NSMutableArray array];
362
+ for (AVCaptureDevice* d in AVCaptureDevice.devices)
363
+ {
364
+ if ([d hasMediaType: AVMediaTypeVideo])
365
+ [devices addObject: d];
366
+ }
367
+ return devices;
368
+ }
369
+
370
+ static AVCaptureDevice*
371
+ get_default_video_device ()
372
+ {
373
+ AVCaptureDevice* device =
374
+ [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
375
+ if (!device)
376
+ rays_error(__FILE__, __LINE__, "Default camera device is not found.");
377
+
378
+ return device;
379
+ }
380
+
381
+ static AVCaptureDevice*
382
+ get_video_device (const char* name)
383
+ {
384
+ if (!name || *name == 0)
385
+ return get_default_video_device();
386
+
387
+ for (AVCaptureDevice* d in get_video_devices())
388
+ {
389
+ if (strcmp(name, d.localizedName.UTF8String) == 0)
390
+ return d;
391
+ }
392
+
393
+ rays_error(__FILE__, __LINE__, "Camera device '%s' is not found.", name);
394
+ return nil;
395
+ }
396
+
397
+ std::vector<String>
398
+ get_camera_device_names ()
399
+ {
400
+ std::vector<String> names;
401
+ for (AVCaptureDevice* d in get_video_devices())
402
+ names.emplace_back(d.localizedName.UTF8String);
403
+ return names;
404
+ }
405
+
406
+
407
+ Camera::Camera (
408
+ const char* device_name,
409
+ int min_width, int min_height, bool resize, bool crop)
410
+ {
411
+ if (device_name)
412
+ self->device_name = device_name;
413
+
414
+ self->min_width = min_width;
415
+ self->min_height = min_height;
416
+ self->resize = resize;
417
+ self->crop = crop;
418
+ }
419
+
420
+ Camera::~Camera ()
421
+ {
422
+ stop();
423
+ }
424
+
425
+ bool
426
+ Camera::start ()
427
+ {
428
+ if (!self->video_input) self->video_input = [[VideoInput alloc] init];
429
+
430
+ AVCaptureDevice* device = get_video_device(self->device_name.c_str());
431
+ return [self->video_input start: device preset: self->get_preset(device)];
432
+ }
433
+
434
+ void
435
+ Camera::stop ()
436
+ {
437
+ if (!self->video_input) return;
438
+
439
+ [self->video_input stop];
440
+ [self->video_input release];
441
+ self->video_input = nil;
442
+ }
443
+
444
+ bool
445
+ Camera::is_active () const
446
+ {
447
+ return self->video_input && [self->video_input isActive];
448
+ }
449
+
450
+ void
451
+ Camera::set_min_width (int width)
452
+ {
453
+ self->min_width = width;
454
+ }
455
+
456
+ int
457
+ Camera::min_width () const
458
+ {
459
+ return self->min_width;
460
+ }
461
+
462
+ void
463
+ Camera::set_min_height (int height)
464
+ {
465
+ self->min_height = height;
466
+ }
467
+
468
+ int
469
+ Camera::min_height () const
470
+ {
471
+ return self->min_height;
472
+ }
473
+
474
+ void
475
+ Camera::set_resize (bool resize)
476
+ {
477
+ self->resize = resize;
478
+ }
479
+
480
+ bool
481
+ Camera::is_resize () const
482
+ {
483
+ return self->resize;
484
+ }
485
+
486
+ void
487
+ Camera::set_crop (bool crop)
488
+ {
489
+ self->crop = crop;
490
+ }
491
+
492
+ bool
493
+ Camera::is_crop () const
494
+ {
495
+ return self->crop;
496
+ }
497
+
498
+ const Image*
499
+ Camera::image () const
500
+ {
501
+ self->update_image_from_video_input();
502
+ return self->image ? &self->image : NULL;
503
+ }
504
+
505
+ Camera::operator bool () const
506
+ {
507
+ return true;
508
+ }
509
+
510
+ bool
511
+ Camera::operator ! () const
512
+ {
513
+ return !operator bool();
514
+ }
515
+
516
+
517
+ }// Rays