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.
@@ -1,7 +1,7 @@
1
1
  // -*- c++ -*-
2
2
  #pragma once
3
- #ifndef __RAYS_SRC_OSX_HELPER_H__
4
- #define __RAYS_SRC_OSX_HELPER_H__
3
+ #ifndef __RAYS_SRC_IOS_HELPER_H__
4
+ #define __RAYS_SRC_IOS_HELPER_H__
5
5
 
6
6
 
7
7
  #include <memory>
@@ -12,7 +12,9 @@ namespace Rays
12
12
  {
13
13
 
14
14
 
15
- void Bitmap_copy_pixels (Bitmap* bitmap, CGImageRef image);
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
@@ -175,8 +175,12 @@ namespace Rays
175
175
  }
176
176
 
177
177
  void
178
- Bitmap_copy_pixels (Bitmap* bitmap, CGImageRef image)
178
+ Bitmap_draw_image (
179
+ Bitmap* bitmap, CGImageRef image,
180
+ coord x, coord y, coord width, coord height)
179
181
  {
182
+ if (width == 0 || height == 0) return;
183
+
180
184
  if (!bitmap || !image)
181
185
  argument_error(__FILE__, __LINE__);
182
186
 
@@ -184,9 +188,9 @@ namespace Rays
184
188
  if (!context)
185
189
  rays_error(__FILE__, __LINE__, "getting CGContext failed.");
186
190
 
187
- size_t width = CGImageGetWidth(image);
188
- size_t height = CGImageGetHeight(image);
189
- CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
191
+ if (width < 0) width = (coord) CGImageGetWidth(image);
192
+ if (height < 0) height = (coord) CGImageGetHeight(image);
193
+ CGContextDrawImage(context, CGRectMake(x, y, width, height), image);
190
194
 
191
195
  Bitmap_set_modified(bitmap);
192
196
  }
@@ -265,7 +269,7 @@ namespace Rays
265
269
  if (!bmp)
266
270
  rays_error(__FILE__, __LINE__, "invalid bitmap.");
267
271
 
268
- Bitmap_copy_pixels(&bmp, image);
272
+ Bitmap_draw_image(&bmp, image);
269
273
  return bmp;
270
274
  }
271
275
 
@@ -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,9 @@ static int video_input_queue_index = 0;
16
17
  @implementation VideoInput
17
18
 
18
19
  {
19
- AVCaptureSession* captureSession;
20
- dispatch_queue_t captureQueue;
21
- CGImageRef captureImage;
20
+ AVCaptureSession* session;
21
+ dispatch_queue_t queue;
22
+ CGImageRef image;
22
23
  }
23
24
 
24
25
  - (id) init
@@ -26,9 +27,9 @@ static int video_input_queue_index = 0;
26
27
  self = [super init];
27
28
  if (self)
28
29
  {
29
- captureSession = nil;
30
- captureQueue = nil;
31
- captureImage = nil;
30
+ session = nil;
31
+ queue = nil;
32
+ image = nil;
32
33
  }
33
34
  return self;
34
35
  }
@@ -38,37 +39,37 @@ static int video_input_queue_index = 0;
38
39
  [self stop];
39
40
  [self clearImage];
40
41
 
41
- if (captureQueue)
42
+ if (queue)
42
43
  {
43
- dispatch_release(captureQueue);
44
- captureQueue = nil;
44
+ dispatch_release(queue);
45
+ queue = nil;
45
46
  }
46
47
 
47
48
  [super dealloc];
48
49
  }
49
50
 
50
- - (dispatch_queue_t) queue
51
+ - (dispatch_queue_t) getQueue
51
52
  {
52
- if (!captureQueue)
53
+ if (!queue)
53
54
  {
54
55
  auto name = Xot::stringf(
55
56
  "org.xord.RaysVideoInputQueue_%d",
56
57
  video_input_queue_index++);
57
- captureQueue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL);
58
+ queue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL);
58
59
  }
59
- return captureQueue;
60
+ return queue;
60
61
  }
61
62
 
62
- - (BOOL) start
63
+ - (BOOL) start: (AVCaptureDevice*) device
64
+ preset: (AVCaptureSessionPreset) preset
63
65
  {
64
- [self stop];
66
+ if (!device) return NO;
65
67
 
66
- AVCaptureSession* session = [[[AVCaptureSession alloc] init] autorelease];
67
- session.sessionPreset = AVCaptureSessionPresetHigh;
68
+ [self stop];
68
69
 
69
- AVCaptureDevice* device =
70
- [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
71
- if (!device) return NO;
70
+ AVCaptureSession* sess = [[[AVCaptureSession alloc] init] autorelease];
71
+ if (preset != nil)
72
+ sess.sessionPreset = preset;
72
73
 
73
74
  //device.activeVideoMinFrameDuration = CMTimeMake(1, 30);
74
75
 
@@ -76,7 +77,7 @@ static int video_input_queue_index = 0;
76
77
  AVCaptureDeviceInput* input = [[[AVCaptureDeviceInput alloc]
77
78
  initWithDevice: device error: &error]
78
79
  autorelease];
79
- if (!input || error || ![session canAddInput: input])
80
+ if (!input || error || ![sess canAddInput: input])
80
81
  return NO;
81
82
 
82
83
  AVCaptureVideoDataOutput* output =
@@ -85,15 +86,15 @@ static int video_input_queue_index = 0;
85
86
  (NSString*) kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)
86
87
  };
87
88
  output.alwaysDiscardsLateVideoFrames = YES;
88
- [output setSampleBufferDelegate: self queue: self.queue];
89
- if (![session canAddOutput: output])
89
+ [output setSampleBufferDelegate: self queue: [self getQueue]];
90
+ if (![sess canAddOutput: output])
90
91
  return NO;
91
92
 
92
- [session addInput: input];
93
- [session addOutput: output];
94
- [session startRunning];
93
+ [sess addInput: input];
94
+ [sess addOutput: output];
95
+ [sess startRunning];
95
96
 
96
- captureSession = [session retain];
97
+ session = [sess retain];
97
98
  return YES;
98
99
  }
99
100
 
@@ -115,35 +116,35 @@ static int video_input_queue_index = 0;
115
116
 
116
117
  dispatch_async(dispatch_get_main_queue(), ^{
117
118
  [self clearImage];
118
- captureImage = cgImage;
119
+ image = cgImage;
119
120
  });
120
121
  }
121
122
 
122
123
  - (void) stop
123
124
  {
124
- if (!captureSession) return;
125
+ if (!session) return;
125
126
 
126
- [captureSession stopRunning];
127
- [captureSession release];
128
- captureSession = nil;
127
+ [session stopRunning];
128
+ [session release];
129
+ session = nil;
129
130
  }
130
131
 
131
132
  - (BOOL) isActive
132
133
  {
133
- return captureSession != nil;
134
+ return session != nil;
134
135
  }
135
136
 
136
137
  - (void) clearImage
137
138
  {
138
- if (!captureImage) return;
139
+ if (!image) return;
139
140
 
140
- CGImageRelease(captureImage);
141
- captureImage = nil;
141
+ CGImageRelease(image);
142
+ image = nil;
142
143
  }
143
144
 
144
145
  - (CGImageRef) getImage
145
146
  {
146
- return captureImage;
147
+ return image;
147
148
  }
148
149
 
149
150
  @end// VideoInput
@@ -156,10 +157,51 @@ namespace Rays
156
157
  struct Camera::Data
157
158
  {
158
159
 
160
+ String device_name;
161
+
162
+ int min_width = -1, min_height = -1;
163
+
164
+ bool resize = false, crop = false;
165
+
159
166
  mutable Image image;
160
167
 
161
168
  VideoInput* video_input = nil;
162
169
 
170
+ AVCaptureSessionPreset get_preset (AVCaptureDevice* device)
171
+ {
172
+ int w = min_width, h = min_height;
173
+ if (w > 0 && h > 0)
174
+ {
175
+ #define SUPPORT(x) \
176
+ [device supportsAVCaptureSessionPreset: AVCaptureSessionPreset##x]
177
+
178
+ if (w <= 320 && h <= 240 && SUPPORT(320x240))
179
+ return AVCaptureSessionPreset320x240;
180
+
181
+ if (w <= 352 && h <= 288 && SUPPORT(352x288))
182
+ return AVCaptureSessionPreset352x288;
183
+
184
+ if (w <= 640 && h <= 480 && SUPPORT(640x480))
185
+ return AVCaptureSessionPreset640x480;
186
+
187
+ if (w <= 960 && h <= 540 && SUPPORT(960x540))
188
+ return AVCaptureSessionPreset960x540;
189
+
190
+ if (/*w <= 1280 && h <= 720 &&*/ SUPPORT(1280x720))
191
+ return AVCaptureSessionPreset1280x720;
192
+
193
+ //if (w <= 1920 && h <= 1080 && SUPPORT(1920x1080))
194
+ // return AVCaptureSessionPreset1920x1080;
195
+
196
+ //if (SUPPORT(3840x2160))
197
+ // return AVCaptureSessionPreset3840x2160;
198
+
199
+ #undef SUPPORT
200
+ }
201
+
202
+ return nil;
203
+ }
204
+
163
205
  void update_image_from_video_input () const
164
206
  {
165
207
  if (!video_input) return;
@@ -167,24 +209,147 @@ namespace Rays
167
209
  CGImageRef cgImage = [video_input getImage];
168
210
  if (!cgImage) return;
169
211
 
170
- if (!image)
212
+ coord draw_x, draw_y, draw_width, draw_height;
213
+ int bitmap_width, bitmap_height;
214
+ get_draw_bounds(
215
+ &draw_x, &draw_y, &draw_width, &draw_height,
216
+ &bitmap_width, &bitmap_height,
217
+ cgImage);
218
+
219
+ if (
220
+ !image ||
221
+ image.bitmap().width() != bitmap_width ||
222
+ image.bitmap().height() != bitmap_height)
171
223
  {
172
- Bitmap bmp(
173
- (int) CGImageGetWidth(cgImage),
174
- (int) CGImageGetHeight(cgImage));
175
- image = Image(bmp);
224
+ image = Image(Bitmap(bitmap_width, bitmap_height));
176
225
  }
177
226
 
178
- Bitmap_copy_pixels(&image.bitmap(), cgImage);
227
+ Bitmap_draw_image(
228
+ &image.bitmap(), cgImage,
229
+ draw_x, draw_y, draw_width, draw_height);
179
230
 
180
231
  [video_input clearImage];
181
232
  }
182
233
 
234
+ void get_draw_bounds (
235
+ coord* draw_x, coord* draw_y, coord* draw_width, coord* draw_height,
236
+ int* bitmap_width, int* bitmap_height,
237
+ CGImageRef image) const
238
+ {
239
+ int image_width = (int) CGImageGetWidth(image);
240
+ int image_height = (int) CGImageGetHeight(image);
241
+ float image_ratio = (float) image_width / (float) image_height;
242
+
243
+ if (resize && min_width > 0 && min_height > 0)
244
+ {
245
+ float min_size_ratio = (float) min_width / (float) min_height;
246
+ if (image_ratio > min_size_ratio)
247
+ {
248
+ *draw_width = min_height * image_ratio;
249
+ *draw_height = min_height;
250
+ }
251
+ else
252
+ {
253
+ *draw_width = min_width;
254
+ *draw_height = min_width / image_ratio;
255
+ }
256
+ }
257
+ else if (resize && min_width > 0)
258
+ {
259
+ *draw_width = min_width;
260
+ *draw_height = min_width / image_ratio;
261
+ }
262
+ else if (resize && min_height > 0)
263
+ {
264
+ *draw_width = min_height * image_ratio;
265
+ *draw_height = min_height;
266
+ }
267
+ else
268
+ {
269
+ *draw_width = image_width;
270
+ *draw_height = image_height;
271
+ }
272
+
273
+ *draw_x = 0;
274
+ *draw_y = 0;
275
+ *bitmap_width = *draw_width;
276
+ *bitmap_height = *draw_height;
277
+
278
+ if (crop && min_width > 0)
279
+ {
280
+ *draw_x = min_width / 2 - *draw_width / 2;
281
+ *bitmap_width = min_width;
282
+ }
283
+ else if (crop && min_height > 0)
284
+ {
285
+ *draw_y = min_height / 2 - *draw_height / 2;
286
+ *bitmap_height = min_height;
287
+ }
288
+ }
289
+
183
290
  };// Camera::Data
184
291
 
185
292
 
186
- Camera::Camera ()
293
+ static NSArray<AVCaptureDevice*>*
294
+ get_video_devices ()
187
295
  {
296
+ NSMutableArray<AVCaptureDevice*>* devices = [NSMutableArray array];
297
+ for (AVCaptureDevice* d in AVCaptureDevice.devices)
298
+ {
299
+ if ([d hasMediaType: AVMediaTypeVideo])
300
+ [devices addObject: d];
301
+ }
302
+ return devices;
303
+ }
304
+
305
+ static AVCaptureDevice*
306
+ get_default_video_device ()
307
+ {
308
+ AVCaptureDevice* device =
309
+ [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
310
+ if (!device)
311
+ rays_error(__FILE__, __LINE__, "Default camera device is not found.");
312
+
313
+ return device;
314
+ }
315
+
316
+ static AVCaptureDevice*
317
+ get_video_device (const char* name)
318
+ {
319
+ if (!name || *name == 0)
320
+ return get_default_video_device();
321
+
322
+ for (AVCaptureDevice* d in get_video_devices())
323
+ {
324
+ if (strcmp(name, d.localizedName.UTF8String) == 0)
325
+ return d;
326
+ }
327
+
328
+ rays_error(__FILE__, __LINE__, "Camera device '%s' is not found.", name);
329
+ return nil;
330
+ }
331
+
332
+ std::vector<String>
333
+ get_camera_device_names ()
334
+ {
335
+ std::vector<String> names;
336
+ for (AVCaptureDevice* d in get_video_devices())
337
+ names.emplace_back(d.localizedName.UTF8String);
338
+ return names;
339
+ }
340
+
341
+
342
+ Camera::Camera (
343
+ const char* device_name,
344
+ int min_width, int min_height, bool resize, bool crop)
345
+ {
346
+ if (device_name)
347
+ self->device_name = device_name;
348
+
349
+ self->min_width = min_width;
350
+ self->min_height = min_height;
351
+ self->resize = resize;
352
+ self->crop = crop;
188
353
  }
189
354
 
190
355
  Camera::~Camera ()
@@ -197,7 +362,9 @@ namespace Rays
197
362
  Camera::start ()
198
363
  {
199
364
  if (!self->video_input) self->video_input = [[VideoInput alloc] init];
200
- return [self->video_input start];
365
+
366
+ AVCaptureDevice* device = get_video_device(self->device_name.c_str());
367
+ return [self->video_input start: device preset: self->get_preset(device)];
201
368
  }
202
369
 
203
370
  void
@@ -214,6 +381,54 @@ namespace Rays
214
381
  return self->video_input && [self->video_input isActive];
215
382
  }
216
383
 
384
+ void
385
+ Camera::set_min_width (int width)
386
+ {
387
+ self->min_width = width;
388
+ }
389
+
390
+ int
391
+ Camera::min_width () const
392
+ {
393
+ return self->min_width;
394
+ }
395
+
396
+ void
397
+ Camera::set_min_height (int height)
398
+ {
399
+ self->min_height = height;
400
+ }
401
+
402
+ int
403
+ Camera::min_height () const
404
+ {
405
+ return self->min_height;
406
+ }
407
+
408
+ void
409
+ Camera::set_resize (bool resize)
410
+ {
411
+ self->resize = resize;
412
+ }
413
+
414
+ bool
415
+ Camera::is_resize () const
416
+ {
417
+ return self->resize;
418
+ }
419
+
420
+ void
421
+ Camera::set_crop (bool crop)
422
+ {
423
+ self->crop = crop;
424
+ }
425
+
426
+ bool
427
+ Camera::is_crop () const
428
+ {
429
+ return self->crop;
430
+ }
431
+
217
432
  const Image*
218
433
  Camera::image () const
219
434
  {