rays 0.1.16 → 0.1.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  {