Merge f9f864883d
into 45b0271ded
This commit is contained in:
commit
32a7e62c6c
|
@ -87,6 +87,7 @@ objc_library(
|
||||||
"//mediapipe/framework:calculator_cc_proto",
|
"//mediapipe/framework:calculator_cc_proto",
|
||||||
"//mediapipe/tasks/cc/core:mediapipe_builtin_op_resolver",
|
"//mediapipe/tasks/cc/core:mediapipe_builtin_op_resolver",
|
||||||
"//mediapipe/tasks/cc/core:task_runner",
|
"//mediapipe/tasks/cc/core:task_runner",
|
||||||
|
"//mediapipe/tasks/ios/common:MPPCommon",
|
||||||
"//mediapipe/tasks/ios/common/utils:MPPCommonUtils",
|
"//mediapipe/tasks/ios/common/utils:MPPCommonUtils",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "mediapipe/tasks/ios/core/sources/MPPTaskRunner.h"
|
#import "mediapipe/tasks/ios/core/sources/MPPTaskRunner.h"
|
||||||
|
#import "mediapipe/tasks/ios/common/sources/MPPCommon.h"
|
||||||
#import "mediapipe/tasks/ios/common/utils/sources/MPPCommonUtils.h"
|
#import "mediapipe/tasks/ios/common/utils/sources/MPPCommonUtils.h"
|
||||||
|
|
||||||
#include "mediapipe/tasks/cc/core/mediapipe_builtin_op_resolver.h"
|
#include "mediapipe/tasks/cc/core/mediapipe_builtin_op_resolver.h"
|
||||||
|
@ -28,6 +29,7 @@ using TaskRunnerCpp = ::mediapipe::tasks::core::TaskRunner;
|
||||||
@interface MPPTaskRunner () {
|
@interface MPPTaskRunner () {
|
||||||
// Cpp Task Runner
|
// Cpp Task Runner
|
||||||
std::unique_ptr<TaskRunnerCpp> _cppTaskRunner;
|
std::unique_ptr<TaskRunnerCpp> _cppTaskRunner;
|
||||||
|
BOOL _initializedWithPacketsCallback;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -46,6 +48,7 @@ using TaskRunnerCpp = ::mediapipe::tasks::core::TaskRunner;
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
_cppTaskRunner = std::move(taskRunnerResult.value());
|
_cppTaskRunner = std::move(taskRunnerResult.value());
|
||||||
|
_initializedWithPacketsCallback = packetsCallback ? YES : NO;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +62,20 @@ using TaskRunnerCpp = ::mediapipe::tasks::core::TaskRunner;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)sendPacketMap:(const PacketMap &)packetMap error:(NSError **)error {
|
- (BOOL)sendPacketMap:(const PacketMap &)packetMap error:(NSError **)error {
|
||||||
|
if (!_initializedWithPacketsCallback) {
|
||||||
|
[MPPCommonUtils
|
||||||
|
createCustomError:error
|
||||||
|
withCode:MPPTasksErrorCodeFailedPreconditionError
|
||||||
|
description:[NSString
|
||||||
|
stringWithFormat:@"This method can only be called if the task is "
|
||||||
|
@"running in a stream mode and an object of a class "
|
||||||
|
@"is provided as the delegate in the task options "
|
||||||
|
@"to receive the results asynchronously."]];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
absl::Status sendStatus = _cppTaskRunner->Send(packetMap);
|
absl::Status sendStatus = _cppTaskRunner->Send(packetMap);
|
||||||
|
|
||||||
return [MPPCommonUtils checkCppError:sendStatus toError:error];
|
return [MPPCommonUtils checkCppError:sendStatus toError:error];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -439,7 +439,7 @@ static NSString *const kLiveStreamTestsDictExpectationKey = @"expectation";
|
||||||
|
|
||||||
#pragma mark Running Mode Tests
|
#pragma mark Running Mode Tests
|
||||||
|
|
||||||
- (void)testCreateImageClassifierFailsWithDelegateInNonLiveStreamMode {
|
- (void)testCreateImageClassifierSucceedsWithDelegateInNonLiveStreamMode {
|
||||||
MPPRunningMode runningModesToTest[] = {MPPRunningModeImage, MPPRunningModeVideo};
|
MPPRunningMode runningModesToTest[] = {MPPRunningModeImage, MPPRunningModeVideo};
|
||||||
for (int i = 0; i < sizeof(runningModesToTest) / sizeof(runningModesToTest[0]); i++) {
|
for (int i = 0; i < sizeof(runningModesToTest) / sizeof(runningModesToTest[0]); i++) {
|
||||||
MPPImageClassifierOptions *options = [self imageClassifierOptionsWithModelName:kFloatModelName];
|
MPPImageClassifierOptions *options = [self imageClassifierOptionsWithModelName:kFloatModelName];
|
||||||
|
@ -447,36 +447,20 @@ static NSString *const kLiveStreamTestsDictExpectationKey = @"expectation";
|
||||||
options.runningMode = runningModesToTest[i];
|
options.runningMode = runningModesToTest[i];
|
||||||
options.imageClassifierLiveStreamDelegate = self;
|
options.imageClassifierLiveStreamDelegate = self;
|
||||||
|
|
||||||
[self
|
MPPImageClassifier *imageClassifier = [[MPPImageClassifier alloc] initWithOptions:options
|
||||||
assertCreateImageClassifierWithOptions:options
|
error:nil];
|
||||||
failsWithExpectedError:
|
XCTAssertNotNil(imageClassifier);
|
||||||
[NSError
|
|
||||||
errorWithDomain:kExpectedErrorDomain
|
|
||||||
code:MPPTasksErrorCodeInvalidArgumentError
|
|
||||||
userInfo:@{
|
|
||||||
NSLocalizedDescriptionKey :
|
|
||||||
@"The vision task is in image or video mode. The "
|
|
||||||
@"delegate must not be set in the task's options."
|
|
||||||
}]];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testCreateImageClassifierFailsWithMissingDelegateInLiveStreamMode {
|
- (void)testCreateImageClassifieSucceedsWithMissingDelegateInLiveStreamMode {
|
||||||
MPPImageClassifierOptions *options = [self imageClassifierOptionsWithModelName:kFloatModelName];
|
MPPImageClassifierOptions *options = [self imageClassifierOptionsWithModelName:kFloatModelName];
|
||||||
|
|
||||||
options.runningMode = MPPRunningModeLiveStream;
|
options.runningMode = MPPRunningModeLiveStream;
|
||||||
|
|
||||||
[self assertCreateImageClassifierWithOptions:options
|
MPPImageClassifier *imageClassifier = [[MPPImageClassifier alloc] initWithOptions:options
|
||||||
failsWithExpectedError:
|
error:nil];
|
||||||
[NSError errorWithDomain:kExpectedErrorDomain
|
XCTAssertNotNil(imageClassifier);
|
||||||
code:MPPTasksErrorCodeInvalidArgumentError
|
|
||||||
userInfo:@{
|
|
||||||
NSLocalizedDescriptionKey :
|
|
||||||
@"The vision task is in live stream mode. An "
|
|
||||||
@"object must be set as the delegate of the task "
|
|
||||||
@"in its options to ensure asynchronous delivery "
|
|
||||||
@"of results."
|
|
||||||
}]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testClassifyFailsWithCallingWrongApiInImageMode {
|
- (void)testClassifyFailsWithCallingWrongApiInImageMode {
|
||||||
|
@ -614,6 +598,30 @@ static NSString *const kLiveStreamTestsDictExpectationKey = @"expectation";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)testClassifyFailsWithMissingDelegateInLiveStreamMode {
|
||||||
|
MPPImageClassifierOptions *options = [self imageClassifierOptionsWithModelName:kFloatModelName];
|
||||||
|
options.runningMode = MPPRunningModeLiveStream;
|
||||||
|
|
||||||
|
MPPImageClassifier *imageClassifier = [self imageClassifierWithOptionsSucceeds:options];
|
||||||
|
|
||||||
|
NSError *expectedError =
|
||||||
|
[NSError errorWithDomain:kExpectedErrorDomain
|
||||||
|
code:MPPTasksErrorCodeFailedPreconditionError
|
||||||
|
userInfo:@{
|
||||||
|
NSLocalizedDescriptionKey :
|
||||||
|
@"This method can only be called if the task is running in a stream "
|
||||||
|
@"mode and an object of a class is provided as the delegate in the "
|
||||||
|
@"task options to receive the results asynchronously."
|
||||||
|
}];
|
||||||
|
|
||||||
|
MPPImage *image = [self imageWithFileInfo:kBurgerImage];
|
||||||
|
|
||||||
|
NSError *error = nil;
|
||||||
|
XCTAssertFalse([imageClassifier classifyAsyncImage:image timestampInMilliseconds:1 error:&error]);
|
||||||
|
|
||||||
|
AssertEqualErrors(error, expectedError);
|
||||||
|
}
|
||||||
|
|
||||||
- (void)testClassifyWithOutOfOrderTimestampsAndLiveStreamModeFails {
|
- (void)testClassifyWithOutOfOrderTimestampsAndLiveStreamModeFails {
|
||||||
MPPImageClassifierOptions *options = [self imageClassifierOptionsWithModelName:kFloatModelName];
|
MPPImageClassifierOptions *options = [self imageClassifierOptionsWithModelName:kFloatModelName];
|
||||||
|
|
||||||
|
|
|
@ -51,38 +51,13 @@ static NSString *const kTaskPrefix = @"com.mediapipe.tasks.vision";
|
||||||
runningMode:(MPPRunningMode)runningMode
|
runningMode:(MPPRunningMode)runningMode
|
||||||
packetsCallback:(PacketsCallback)packetsCallback
|
packetsCallback:(PacketsCallback)packetsCallback
|
||||||
error:(NSError **)error {
|
error:(NSError **)error {
|
||||||
switch (runningMode) {
|
|
||||||
case MPPRunningModeImage:
|
if (_runningMode > MPPRunningModeLiveStream) {
|
||||||
case MPPRunningModeVideo: {
|
|
||||||
if (packetsCallback) {
|
|
||||||
[MPPCommonUtils createCustomError:error
|
|
||||||
withCode:MPPTasksErrorCodeInvalidArgumentError
|
|
||||||
description:@"The vision task is in image or video mode. The "
|
|
||||||
@"delegate must not be set in the task's options."];
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MPPRunningModeLiveStream: {
|
|
||||||
if (!packetsCallback) {
|
|
||||||
[MPPCommonUtils
|
|
||||||
createCustomError:error
|
|
||||||
withCode:MPPTasksErrorCodeInvalidArgumentError
|
|
||||||
description:
|
|
||||||
@"The vision task is in live stream mode. An object must be set as the "
|
|
||||||
@"delegate of the task in its options to ensure asynchronous delivery of "
|
|
||||||
@"results."];
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
[MPPCommonUtils createCustomError:error
|
[MPPCommonUtils createCustomError:error
|
||||||
withCode:MPPTasksErrorCodeInvalidArgumentError
|
withCode:MPPTasksErrorCodeInvalidArgumentError
|
||||||
description:@"Unrecognized running mode"];
|
description:@"Unrecognized running mode"];
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
_runningMode = runningMode;
|
_runningMode = runningMode;
|
||||||
self = [super initWithCalculatorGraphConfig:graphConfig
|
self = [super initWithCalculatorGraphConfig:graphConfig
|
||||||
|
|
|
@ -64,11 +64,6 @@ static const int kMicroSecondsPerMilliSecond = 1000;
|
||||||
@implementation MPPImageClassifier
|
@implementation MPPImageClassifier
|
||||||
|
|
||||||
- (void)processLiveStreamResult:(absl::StatusOr<PacketMap>)liveStreamResult {
|
- (void)processLiveStreamResult:(absl::StatusOr<PacketMap>)liveStreamResult {
|
||||||
if (![self.imageClassifierLiveStreamDelegate
|
|
||||||
respondsToSelector:@selector
|
|
||||||
(imageClassifier:didFinishClassificationWithResult:timestampInMilliseconds:error:)]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSError *callbackError = nil;
|
NSError *callbackError = nil;
|
||||||
if (![MPPCommonUtils checkCppError:liveStreamResult.status() toError:&callbackError]) {
|
if (![MPPCommonUtils checkCppError:liveStreamResult.status() toError:&callbackError]) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
NS_SWIFT_NAME(ImageClassifierLiveStreamDelegate)
|
NS_SWIFT_NAME(ImageClassifierLiveStreamDelegate)
|
||||||
@protocol MPPImageClassifierLiveStreamDelegate <NSObject>
|
@protocol MPPImageClassifierLiveStreamDelegate <NSObject>
|
||||||
|
|
||||||
@optional
|
@required
|
||||||
/**
|
/**
|
||||||
* This method notifies a delegate that the results of asynchronous classification of
|
* This method notifies a delegate that the results of asynchronous classification of
|
||||||
* an image submitted to the `ImageClassifier` is available.
|
* an image submitted to the `ImageClassifier` is available.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user