diff --git a/mediapipe/tasks/ios/vision/image_classifier/BUILD b/mediapipe/tasks/ios/vision/image_classifier/BUILD index 69490f71..cf89249c 100644 --- a/mediapipe/tasks/ios/vision/image_classifier/BUILD +++ b/mediapipe/tasks/ios/vision/image_classifier/BUILD @@ -55,7 +55,6 @@ objc_library( "//mediapipe/tasks/ios/common/utils:MPPCommonUtils", "//mediapipe/tasks/ios/common/utils:NSStringHelpers", "//mediapipe/tasks/ios/core:MPPTaskInfo", - "//mediapipe/tasks/ios/core:MPPTaskOptions", "//mediapipe/tasks/ios/vision/core:MPPImage", "//mediapipe/tasks/ios/vision/core:MPPVisionPacketCreator", "//mediapipe/tasks/ios/vision/core:MPPVisionTaskRunner", diff --git a/mediapipe/tasks/ios/vision/image_classifier/sources/MPPImageClassifier.h b/mediapipe/tasks/ios/vision/image_classifier/sources/MPPImageClassifier.h index 398236bb..6b81a240 100644 --- a/mediapipe/tasks/ios/vision/image_classifier/sources/MPPImageClassifier.h +++ b/mediapipe/tasks/ios/vision/image_classifier/sources/MPPImageClassifier.h @@ -14,7 +14,6 @@ #import -#import "mediapipe/tasks/ios/core/sources/MPPTaskOptions.h" #import "mediapipe/tasks/ios/vision/core/sources/MPPImage.h" #import "mediapipe/tasks/ios/vision/image_classifier/sources/MPPImageClassifierOptions.h" #import "mediapipe/tasks/ios/vision/image_classifier/sources/MPPImageClassifierResult.h" diff --git a/mediapipe/tasks/ios/vision/image_classifier/sources/MPPImageClassifier.mm b/mediapipe/tasks/ios/vision/image_classifier/sources/MPPImageClassifier.mm index 10f6fc26..5d2595cd 100644 --- a/mediapipe/tasks/ios/vision/image_classifier/sources/MPPImageClassifier.mm +++ b/mediapipe/tasks/ios/vision/image_classifier/sources/MPPImageClassifier.mm @@ -55,6 +55,7 @@ static const int kMicroSecondsPerMilliSecond = 1000; @interface MPPImageClassifier () { /** iOS Vision Task Runner */ MPPVisionTaskRunner *_visionTaskRunner; + dispatch_queue_t _callbackQueue; } @property(nonatomic, weak) id imageClassifierLiveStreamDelegate; @@ -62,6 +63,44 @@ static const int kMicroSecondsPerMilliSecond = 1000; @implementation MPPImageClassifier +- (void)processLiveStreamResult:(absl::StatusOr)liveStreamResult { + if (![self.imageClassifierLiveStreamDelegate + respondsToSelector:@selector + (imageClassifier:didFinishClassificationWithResult:timestampInMilliseconds:error:)]) { + return; + } + + NSError *callbackError = nil; + if (![MPPCommonUtils checkCppError:liveStreamResult.status() toError:&callbackError]) { + dispatch_async(_callbackQueue, ^{ + [self.imageClassifierLiveStreamDelegate imageClassifier:self + didFinishClassificationWithResult:nil + timestampInMilliseconds:Timestamp::Unset().Value() + error:callbackError]; + }); + return; + } + + PacketMap &outputPacketMap = liveStreamResult.value(); + if (outputPacketMap[kImageOutStreamName.cppString].IsEmpty()) { + return; + } + + MPPImageClassifierResult *result = [MPPImageClassifierResult + imageClassifierResultWithClassificationsPacket:outputPacketMap[kClassificationsStreamName + .cppString]]; + + NSInteger timeStampInMilliseconds = + outputPacketMap[kImageOutStreamName.cppString].Timestamp().Value() / + kMicroSecondsPerMilliSecond; + dispatch_async(_callbackQueue, ^{ + [self.imageClassifierLiveStreamDelegate imageClassifier:self + didFinishClassificationWithResult:result + timestampInMilliseconds:timeStampInMilliseconds + error:callbackError]; + }); +} + - (instancetype)initWithOptions:(MPPImageClassifierOptions *)options error:(NSError **)error { self = [super init]; if (self) { @@ -88,56 +127,19 @@ static const int kMicroSecondsPerMilliSecond = 1000; if (options.imageClassifierLiveStreamDelegate) { _imageClassifierLiveStreamDelegate = options.imageClassifierLiveStreamDelegate; - // Capturing `self` as weak in order to avoid `self` being kept in memory - // and cause a retain cycle, after self is set to `nil`. - MPPImageClassifier *__weak weakSelf = self; // Create a private serial dispatch queue in which the deleagte method will be called // asynchronously. This is to ensure that if the client performs a long running operation in // the delegate method, the queue on which the C++ callbacks is invoked is not blocked and is // freed up to continue with its operations. - const char *queueName = [MPPVisionTaskRunner uniqueDispatchQueueNameWithSuffix:kTaskName]; - dispatch_queue_t callbackQueue = dispatch_queue_create(queueName, NULL); - packetsCallback = [=](absl::StatusOr status_or_packets) { - if (!weakSelf) { - return; - } - if (![weakSelf.imageClassifierLiveStreamDelegate - respondsToSelector:@selector - (imageClassifier: - didFinishClassificationWithResult:timestampInMilliseconds:error:)]) { - return; - } + _callbackQueue = dispatch_queue_create( + [MPPVisionTaskRunner uniqueDispatchQueueNameWithSuffix:kTaskName], NULL); - NSError *callbackError = nil; - if (![MPPCommonUtils checkCppError:status_or_packets.status() toError:&callbackError]) { - dispatch_async(callbackQueue, ^{ - [weakSelf.imageClassifierLiveStreamDelegate imageClassifier:weakSelf - didFinishClassificationWithResult:nil - timestampInMilliseconds:Timestamp::Unset().Value() - error:callbackError]; - }); - return; - } - - PacketMap &outputPacketMap = status_or_packets.value(); - if (outputPacketMap[kImageOutStreamName.cppString].IsEmpty()) { - return; - } - - MPPImageClassifierResult *result = - [MPPImageClassifierResult imageClassifierResultWithClassificationsPacket: - outputPacketMap[kClassificationsStreamName.cppString]]; - - NSInteger timeStampInMilliseconds = - outputPacketMap[kImageOutStreamName.cppString].Timestamp().Value() / - kMicroSecondsPerMilliSecond; - dispatch_async(callbackQueue, ^{ - [weakSelf.imageClassifierLiveStreamDelegate imageClassifier:weakSelf - didFinishClassificationWithResult:result - timestampInMilliseconds:timeStampInMilliseconds - error:callbackError]; - }); + // Capturing `self` as weak in order to avoid `self` being kept in memory + // and cause a retain cycle, after self is set to `nil`. + MPPImageClassifier *__weak weakSelf = self; + packetsCallback = [=](absl::StatusOr liveStreamResult) { + [weakSelf processLiveStreamResult:liveStreamResult]; }; } diff --git a/mediapipe/tasks/ios/vision/object_detector/sources/MPPObjectDetector.mm b/mediapipe/tasks/ios/vision/object_detector/sources/MPPObjectDetector.mm index b7924996..52648af5 100644 --- a/mediapipe/tasks/ios/vision/object_detector/sources/MPPObjectDetector.mm +++ b/mediapipe/tasks/ios/vision/object_detector/sources/MPPObjectDetector.mm @@ -50,12 +50,51 @@ static NSString *const kTaskName = @"objectDetector"; @interface MPPObjectDetector () { /** iOS Vision Task Runner */ MPPVisionTaskRunner *_visionTaskRunner; + dispatch_queue_t _callbackQueue; } @property(nonatomic, weak) id objectDetectorLiveStreamDelegate; @end @implementation MPPObjectDetector +- (void)processLiveStreamResult:(absl::StatusOr)liveStreamResult { + if (![self.objectDetectorLiveStreamDelegate + respondsToSelector:@selector(objectDetector: + didFinishDetectionWithResult:timestampInMilliseconds:error:)]) { + return; + } + + NSError *callbackError = nil; + if (![MPPCommonUtils checkCppError:liveStreamResult.status() toError:&callbackError]) { + dispatch_async(_callbackQueue, ^{ + [self.objectDetectorLiveStreamDelegate objectDetector:self + didFinishDetectionWithResult:nil + timestampInMilliseconds:Timestamp::Unset().Value() + error:callbackError]; + }); + return; + } + + PacketMap &outputPacketMap = liveStreamResult.value(); + if (outputPacketMap[kImageOutStreamName.cppString].IsEmpty()) { + return; + } + + MPPObjectDetectorResult *result = [MPPObjectDetectorResult + objectDetectorResultWithDetectionsPacket: + outputPacketMap[kDetectionsStreamName.cppString]]; + + NSInteger timeStampInMilliseconds = + outputPacketMap[kImageOutStreamName.cppString].Timestamp().Value() / + kMicroSecondsPerMilliSecond; + dispatch_async(_callbackQueue, ^{ + [self.objectDetectorLiveStreamDelegate objectDetector:self + didFinishDetectionWithResult:result + timestampInMilliseconds:timeStampInMilliseconds + error:callbackError]; + }); +} + - (instancetype)initWithOptions:(MPPObjectDetectorOptions *)options error:(NSError **)error { self = [super init]; if (self) { @@ -82,55 +121,18 @@ static NSString *const kTaskName = @"objectDetector"; if (options.objectDetectorLiveStreamDelegate) { _objectDetectorLiveStreamDelegate = options.objectDetectorLiveStreamDelegate; - // Capturing `self` as weak in order to avoid `self` being kept in memory - // and cause a retain cycle, after self is set to `nil`. - MPPObjectDetector *__weak weakSelf = self; - // Create a private serial dispatch queue in which the delegate method will be called // asynchronously. This is to ensure that if the client performs a long running operation in // the delegate method, the queue on which the C++ callbacks is invoked is not blocked and is // freed up to continue with its operations. - dispatch_queue_t callbackQueue = dispatch_queue_create( + _callbackQueue = dispatch_queue_create( [MPPVisionTaskRunner uniqueDispatchQueueNameWithSuffix:kTaskName], NULL); - packetsCallback = [=](absl::StatusOr statusOrPackets) { - if (!weakSelf) { - return; - } - if (![weakSelf.objectDetectorLiveStreamDelegate - respondsToSelector:@selector - (objectDetector:didFinishDetectionWithResult:timestampInMilliseconds:error:)]) { - return; - } - NSError *callbackError = nil; - if (![MPPCommonUtils checkCppError:statusOrPackets.status() toError:&callbackError]) { - dispatch_async(callbackQueue, ^{ - [weakSelf.objectDetectorLiveStreamDelegate objectDetector:weakSelf - didFinishDetectionWithResult:nil - timestampInMilliseconds:Timestamp::Unset().Value() - error:callbackError]; - }); - return; - } - - PacketMap &outputPacketMap = statusOrPackets.value(); - if (outputPacketMap[kImageOutStreamName.cppString].IsEmpty()) { - return; - } - - MPPObjectDetectorResult *result = [MPPObjectDetectorResult - objectDetectorResultWithDetectionsPacket:statusOrPackets - .value()[kDetectionsStreamName.cppString]]; - - NSInteger timeStampInMilliseconds = - outputPacketMap[kImageOutStreamName.cppString].Timestamp().Value() / - kMicroSecondsPerMilliSecond; - dispatch_async(callbackQueue, ^{ - [weakSelf.objectDetectorLiveStreamDelegate objectDetector:weakSelf - didFinishDetectionWithResult:result - timestampInMilliseconds:timeStampInMilliseconds - error:callbackError]; - }); + // Capturing `self` as weak in order to avoid `self` being kept in memory + // and cause a retain cycle, after self is set to `nil`. + MPPObjectDetector *__weak weakSelf = self; + packetsCallback = [=](absl::StatusOr liveStreamResult) { + [weakSelf processLiveStreamResult:liveStreamResult]; }; }