@@ -13,8 +13,11 @@ @interface FirebaseCam : NSObject <FlutterTexture,
13
13
AVCaptureVideoDataOutputSampleBufferDelegate,
14
14
AVCaptureAudioDataOutputSampleBufferDelegate,
15
15
FlutterStreamHandler>
16
+ @property (assign , atomic ) BOOL isRecognizing;
16
17
@property (readonly , nonatomic ) int64_t textureId;
17
18
@property (nonatomic , copy ) void (^onFrameAvailable)();
19
+ @property (nonatomic ) id <Detector> activeDetector;
20
+ @property (nonatomic ) FlutterEventSink resultSink;
18
21
@property (nonatomic ) FlutterEventChannel *eventChannel;
19
22
@property (nonatomic ) FlutterEventSink eventSink;
20
23
@property (readonly , nonatomic ) AVCaptureSession *captureSession;
@@ -140,8 +143,17 @@ - (void)captureOutput:(AVCaptureOutput *)output
140
143
didOutputSampleBuffer : (CMSampleBufferRef)sampleBuffer
141
144
fromConnection : (AVCaptureConnection *)connection {
142
145
CVImageBufferRef newBuffer = CMSampleBufferGetImageBuffer (sampleBuffer);
143
- if (output == _captureVideoOutput) {
144
- CVPixelBufferRef newBuffer = CMSampleBufferGetImageBuffer (sampleBuffer);
146
+ if (newBuffer) {
147
+ if (!_isRecognizing) {
148
+ _isRecognizing = YES ;
149
+ FIRVisionImage *visionImage = [[FIRVisionImage alloc ] initWithBuffer: sampleBuffer];
150
+ FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc ] init ];
151
+ FIRVisionDetectorImageOrientation visionOrientation = FIRVisionDetectorImageOrientationTopLeft;
152
+
153
+ metadata.orientation = visionOrientation;
154
+ visionImage.metadata = metadata;
155
+ [_activeDetector handleDetection: visionImage result: _resultSink];
156
+ }
145
157
CFRetain (newBuffer);
146
158
CVPixelBufferRef old = _latestPixelBuffer;
147
159
while (!OSAtomicCompareAndSwapPtrBarrier (old, newBuffer, (void **)&_latestPixelBuffer)) {
@@ -156,9 +168,9 @@ - (void)captureOutput:(AVCaptureOutput *)output
156
168
}
157
169
if (!CMSampleBufferDataIsReady (sampleBuffer)) {
158
170
_eventSink (@{
159
- @" event" : @" error" ,
160
- @" errorDescription" : @" sample buffer is not ready. Skipping sample"
161
- });
171
+ @" event" : @" error" ,
172
+ @" errorDescription" : @" sample buffer is not ready. Skipping sample"
173
+ });
162
174
return ;
163
175
}
164
176
}
@@ -227,7 +239,7 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
227
239
messenger: [registrar messenger ]];
228
240
[registrar addMethodCallDelegate: instance channel: channel];
229
241
[results setStreamHandler: instance];
230
-
242
+
231
243
SEL sel = NSSelectorFromString (@" registerLibrary:withVersion:" );
232
244
if ([FIRApp respondsToSelector: sel]) {
233
245
[FIRApp performSelector: sel withObject: LIBRARY_NAME withObject: LIBRARY_VERSION];
@@ -264,11 +276,11 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re
264
276
NSString *modelName = call.arguments [@" model" ];
265
277
NSDictionary *options = call.arguments [@" options" ];
266
278
NSNumber *handle = call.arguments [@" handle" ];
267
- if ([@" ModelManager#setupLocalModel" isEqualToString: call.method]) {
268
- [SetupLocalModel modelName: modelName result: result];
269
- } else if ([@" ModelManager#setupRemoteModel" isEqualToString: call.method]) {
270
- [SetupRemoteModel modelName: modelName result: result];
271
- } else if ([@" camerasAvailable" isEqualToString: call.method]){
279
+ if ([@" ModelManager#setupLocalModel" isEqualToString: call.method]) {
280
+ [SetupLocalModel modelName: modelName result: result];
281
+ } else if ([@" ModelManager#setupRemoteModel" isEqualToString: call.method]) {
282
+ [SetupRemoteModel modelName: modelName result: result];
283
+ } else if ([@" camerasAvailable" isEqualToString: call.method]){
272
284
AVCaptureDeviceDiscoverySession *discoverySession = [AVCaptureDeviceDiscoverySession
273
285
discoverySessionWithDeviceTypes: @[ AVCaptureDeviceTypeBuiltInWideAngleCamera ]
274
286
mediaType: AVMediaTypeVideo
@@ -290,20 +302,20 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re
290
302
break ;
291
303
}
292
304
[reply addObject: @{
293
- @" name" : [device uniqueID ],
294
- @" lensFacing" : lensFacing,
295
- @" sensorOrientation" : @90 ,
296
- }];
305
+ @" name" : [device uniqueID ],
306
+ @" lensFacing" : lensFacing,
307
+ @" sensorOrientation" : @90 ,
308
+ }];
297
309
}
298
310
result (reply);
299
311
} else if ([@" initialize" isEqualToString: call.method]) {
300
312
NSString *cameraName = call.arguments [@" cameraName" ];
301
313
NSString *resolutionPreset = call.arguments [@" resolutionPreset" ];
302
314
NSError *error;
303
315
FirebaseCam *cam = [[FirebaseCam alloc ] initWithCameraName: cameraName
304
- resolutionPreset: resolutionPreset
305
- dispatchQueue: _dispatchQueue
306
- error: &error];
316
+ resolutionPreset: resolutionPreset
317
+ dispatchQueue: _dispatchQueue
318
+ error: &error];
307
319
if (error) {
308
320
result (getFlutterError (error));
309
321
} else {
@@ -323,10 +335,10 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re
323
335
[eventChannel setStreamHandler: cam];
324
336
cam.eventChannel = eventChannel;
325
337
result (@{
326
- @" textureId" : @(textureId),
327
- @" previewWidth" : @(cam.previewSize .width ),
328
- @" previewHeight" : @(cam.previewSize .height ),
329
- });
338
+ @" textureId" : @(textureId),
339
+ @" previewWidth" : @(cam.previewSize .width ),
340
+ @" previewHeight" : @(cam.previewSize .height ),
341
+ });
330
342
[cam start ];
331
343
}
332
344
} else if ([@" BarcodeDetector#startDetection" isEqualToString: call.method]){
@@ -335,52 +347,51 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re
335
347
detector = [[BarcodeDetector alloc ] initWithVision: [FIRVision vision ] options: options];
336
348
[FLTFirebaseMlVisionPlugin addDetector: handle detector: detector];
337
349
}
350
+ _camera.activeDetector = detectors[handle];
338
351
} else if ([@" BarcodeDetector#detectInImage" isEqualToString: call.method] ||
339
- [@" FaceDetector#processImage" isEqualToString: call.method] ||
340
- [@" ImageLabeler#processImage" isEqualToString: call.method] ||
341
- [@" TextRecognizer#processImage" isEqualToString: call.method] ||
342
- [@" VisionEdgeImageLabeler#processLocalImage" isEqualToString: call.method] ||
343
- [@" VisionEdgeImageLabeler#processRemoteImage" isEqualToString: call.method]) {
344
- [self handleDetection: call result: result];
345
- } else if ([@" BarcodeDetector#close" isEqualToString: call.method] ||
346
- [@" FaceDetector#close" isEqualToString: call.method] ||
347
- [@" ImageLabeler#close" isEqualToString: call.method] ||
348
- [@" TextRecognizer#close" isEqualToString: call.method] ||
349
- [@" VisionEdgeImageLabeler#close" isEqualToString: call.method]) {
350
- NSNumber *handle = call.arguments [@" handle" ];
351
- [detectors removeObjectForKey: handle];
352
- result (nil );
353
- } else {
354
- result (FlutterMethodNotImplemented);
355
- }
352
+ [@" FaceDetector#processImage" isEqualToString: call.method] ||
353
+ [@" ImageLabeler#processImage" isEqualToString: call.method] ||
354
+ [@" TextRecognizer#processImage" isEqualToString: call.method] ||
355
+ [@" VisionEdgeImageLabeler#processLocalImage" isEqualToString: call.method] ||
356
+ [@" VisionEdgeImageLabeler#processRemoteImage" isEqualToString: call.method]) {
357
+ [self handleDetection: call result: result];
358
+ } else if ([@" BarcodeDetector#close" isEqualToString: call.method] ||
359
+ [@" FaceDetector#close" isEqualToString: call.method] ||
360
+ [@" ImageLabeler#close" isEqualToString: call.method] ||
361
+ [@" TextRecognizer#close" isEqualToString: call.method] ||
362
+ [@" VisionEdgeImageLabeler#close" isEqualToString: call.method]) {
363
+ NSNumber *handle = call.arguments [@" handle" ];
364
+ [detectors removeObjectForKey: handle];
365
+ result (nil );
366
+ } else {
367
+ result (FlutterMethodNotImplemented);
368
+ }
356
369
}
357
370
358
371
- (void )handleDetection : (FlutterMethodCall *)call result : (FlutterResult)result {
359
- FIRVisionImage *image = [self dataToVisionImage: call.arguments];
360
- NSDictionary *options = call.arguments [@" options" ];
361
-
362
- NSNumber *handle = call.arguments [@" handle" ];
363
- id <Detector> detector = detectors[handle];
364
- if (!detector) {
365
- if ([call.method hasPrefix: @" BarcodeDetector" ]) {
366
- detector = [[BarcodeDetector alloc ] initWithVision: [FIRVision vision ] options: options];
367
- } else if ([call.method hasPrefix: @" FaceDetector" ]) {
368
- detector = [[FaceDetector alloc ] initWithVision: [FIRVision vision ] options: options];
369
- } else if ([call.method hasPrefix: @" ImageLabeler" ]) {
370
- detector = [[ImageLabeler alloc ] initWithVision: [FIRVision vision ] options: options];
371
- } else if ([call.method hasPrefix: @" TextRecognizer" ]) {
372
- detector = [[TextRecognizer alloc ] initWithVision: [FIRVision vision ] options: options];
373
- } else if ([call.method isEqualToString: @" VisionEdgeImageLabeler#processLocalImage" ]) {
374
- detector = [[LocalVisionEdgeDetector alloc ] initWithVision: [FIRVision vision ]
375
- options: options];
376
- } else if ([call.method isEqualToString: @" VisionEdgeImageLabeler#processRemoteImage" ]) {
377
- detector = [[RemoteVisionEdgeDetector alloc ] initWithVision: [FIRVision vision ]
378
- options: options];
372
+ FIRVisionImage *image = [self dataToVisionImage: call.arguments];
373
+ NSDictionary *options = call.arguments [@" options" ];
374
+ NSNumber *handle = call.arguments [@" handle" ];
375
+ id <Detector> detector = detectors[handle];
376
+ if (!detector) {
377
+ if ([call.method hasPrefix: @" BarcodeDetector" ]) {
378
+ detector = [[BarcodeDetector alloc ] initWithVision: [FIRVision vision ] options: options];
379
+ } else if ([call.method hasPrefix: @" FaceDetector" ]) {
380
+ detector = [[FaceDetector alloc ] initWithVision: [FIRVision vision ] options: options];
381
+ } else if ([call.method hasPrefix: @" ImageLabeler" ]) {
382
+ detector = [[ImageLabeler alloc ] initWithVision: [FIRVision vision ] options: options];
383
+ } else if ([call.method hasPrefix: @" TextRecognizer" ]) {
384
+ detector = [[TextRecognizer alloc ] initWithVision: [FIRVision vision ] options: options];
385
+ } else if ([call.method isEqualToString: @" VisionEdgeImageLabeler#processLocalImage" ]) {
386
+ detector = [[LocalVisionEdgeDetector alloc ] initWithVision: [FIRVision vision ]
387
+ options: options];
388
+ } else if ([call.method isEqualToString: @" VisionEdgeImageLabeler#processRemoteImage" ]) {
389
+ detector = [[RemoteVisionEdgeDetector alloc ] initWithVision: [FIRVision vision ]
390
+ options: options];
391
+ }
392
+ [FLTFirebaseMlVisionPlugin addDetector: handle detector: detector];
379
393
}
380
- [FLTFirebaseMlVisionPlugin addDetector: handle detector: detector];
381
- }
382
-
383
- [detectors[handle] handleDetection: image result: result];
394
+ [detectors[handle] handleDetection: image result: result];
384
395
}
385
396
386
397
- (FIRVisionImage *)dataToVisionImage : (NSDictionary *)imageData {
@@ -524,13 +535,13 @@ - (FIRVisionImage *)pixelBufferToVisionImage:(CVPixelBufferRef)pixelBufferRef {
524
535
}
525
536
526
537
+ (void )addDetector : (NSNumber *)handle detector : (id <Detector>)detector {
527
- if (detectors[handle]) {
528
- NSString *reason =
538
+ if (detectors[handle]) {
539
+ NSString *reason =
529
540
[[NSString alloc ] initWithFormat: @" Object for handle already exists: %d " , handle.intValue];
530
- @throw [[NSException alloc ] initWithName: NSInvalidArgumentException reason: reason userInfo: nil ];
531
- }
532
-
533
- detectors[handle] = detector;
541
+ @throw [[NSException alloc ] initWithName: NSInvalidArgumentException reason: reason userInfo: nil ];
542
+ }
543
+
544
+ detectors[handle] = detector;
534
545
}
535
546
536
547
- (FlutterError * _Nullable)onCancelWithArguments : (id _Nullable)arguments {
0 commit comments