Commit aa2bc556 authored by junweifu's avatar junweifu Committed by Commit Bot

ShapeDetection: Dispatch asynchronously an image analysis request on a queue

Add AsyncRequest class to submit an image analysis request for asynchronous
execution on a dispatch queue with default priority.

Link Mac 10.13 build bots [2] and Face Detection demo[3] here.
Split original large CL[4] up in smaller subpatches including this CL.

[1] https://cs.chromium.org/chromium/src/base/mac/sdk_forward_declarations.h?sq=package:chromium&dr=CSs&l=5
[2] https://ci.chromium.org/buildbot/chromium.fyi/Chromium%20Mac%2010.13/
[3] https://codepen.io/miguelao/pen/PmJWro
[4] https://chromium-review.googlesource.com/c/chromium/src/+/912780/2

BUG=799319

Cq-Include-Trybots: master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win10_chromium_x64_rel_ng
Change-Id: I993d9f94299db464a109fb284356213413396f37
Reviewed-on: https://chromium-review.googlesource.com/947818Reviewed-by: default avatarMark Mentovai <mark@chromium.org>
Reviewed-by: default avatarMiguel Casas <mcasas@chromium.org>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Commit-Queue: Junwei Fu <junwei.fu@intel.com>
Cr-Commit-Position: refs/heads/master@{#543653}
parent 8cc080c6
......@@ -284,6 +284,15 @@ typedef void (^VNRequestCompletionHandler)(VNRequest* request, NSError* error);
: VNImageBasedRequest<VNFaceObservationAccepting>
@end
// VNImageRequestHandler forward declarations.
typedef NSString* VNImageOption NS_STRING_ENUM;
@interface VNImageRequestHandler : NSObject
- (instancetype)initWithCIImage:(CIImage*)image
options:(NSDictionary<VNImageOption, id>*)options;
- (BOOL)performRequests:(NSArray<VNRequest*>*)requests error:(NSError**)error;
@end
#endif // MAC_OS_X_VERSION_10_13
// ----------------------------------------------------------------------------
// The symbol for kCWSSIDDidChangeNotification is available in the
......
......@@ -5,10 +5,9 @@
#ifndef SERVICES_SHAPE_DETECTION_DETECTION_UTILS_MAC_H_
#define SERVICES_SHAPE_DETECTION_DETECTION_UTILS_MAC_H_
#import <QuartzCore/QuartzCore.h>
#import <CoreImage/CoreImage.h>
#include "base/mac/scoped_nsobject.h"
#include "services/shape_detection/public/mojom/barcodedetection.mojom.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace shape_detection {
......
......@@ -5,11 +5,7 @@
#include "services/shape_detection/detection_utils_mac.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsobject.h"
#include "base/memory/shared_memory.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "services/shape_detection/barcode_detection_impl.h"
#include "skia/ext/skia_utils_mac.h"
#include "base/numerics/checked_math.h"
#include "third_party/skia/include/utils/mac/SkCGUtils.h"
namespace shape_detection {
......
......@@ -5,10 +5,15 @@
#ifndef SERVICES_SHAPE_DETECTION_FACE_DETECTION_IMPL_MAC_VISION_H_
#define SERVICES_SHAPE_DETECTION_FACE_DETECTION_IMPL_MAC_VISION_H_
#include <memory>
#include <utility>
#include "base/mac/availability.h"
#include "base/mac/scoped_nsobject.h"
#include "base/mac/sdk_forward_declarations.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/shape_detection/public/mojom/facedetection.mojom.h"
class SkBitmap;
......@@ -26,8 +31,19 @@ class API_AVAILABLE(macos(10.13)) FaceDetectionImplMacVision
void Detect(const SkBitmap& bitmap,
mojom::FaceDetection::DetectCallback callback) override;
void SetBinding(mojo::StrongBindingPtr<mojom::FaceDetection> binding) {
binding_ = std::move(binding);
}
private:
base::scoped_nsobject<VNDetectFaceLandmarksRequest> landmarks_request_;
class VisionAPIAsyncRequestMac;
void OnFacesDetected(VNRequest* request, NSError* error);
std::unique_ptr<VisionAPIAsyncRequestMac> landmarks_async_request_;
DetectCallback detected_callback_;
mojo::StrongBindingPtr<mojom::FaceDetection> binding_;
base::WeakPtrFactory<FaceDetectionImplMacVision> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FaceDetectionImplMacVision);
};
......
......@@ -6,13 +6,94 @@
#include <dlfcn.h>
#include <objc/runtime.h>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/sys_string_conversions.h"
#include "services/shape_detection/detection_utils_mac.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace shape_detection {
FaceDetectionImplMacVision::FaceDetectionImplMacVision() {
// The VisionAPIAsyncRequestMac class submits an image analysis request for
// asynchronous execution on a dispatch queue with default priority.
class API_AVAILABLE(macos(10.13))
FaceDetectionImplMacVision::VisionAPIAsyncRequestMac {
public:
// A callback run when the asynchronous execution completes. The callback is
// repeating for the instance.
using Callback =
base::RepeatingCallback<void(VNRequest* request, NSError* error)>;
~VisionAPIAsyncRequestMac() = default;
// Creates an VisionAPIAsyncRequestMac instance which sets |callback| to be
// called when the asynchronous action completes.
static std::unique_ptr<VisionAPIAsyncRequestMac> Create(Class request_class,
Callback callback) {
return base::WrapUnique(
new VisionAPIAsyncRequestMac(std::move(callback), request_class));
}
// Processes asynchronously an image analysis request and returns results with
// |callback_| when the asynchronous request completes.
bool PerformRequest(const SkBitmap& bitmap) {
Class image_handler_class = NSClassFromString(@"VNImageRequestHandler");
if (!image_handler_class) {
DLOG(ERROR) << "Failed to create VNImageRequestHandler";
return false;
}
base::scoped_nsobject<CIImage> ci_image = CreateCIImageFromSkBitmap(bitmap);
if (!ci_image) {
DLOG(ERROR) << "Failed to create image from SkBitmap";
return false;
}
base::scoped_nsobject<VNImageRequestHandler> image_handler(
[[image_handler_class alloc] initWithCIImage:ci_image options:@{}]);
if (!image_handler) {
DLOG(ERROR) << "Failed to create image request handler";
return false;
}
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSError* ns_error = nil;
if ([image_handler performRequests:@[ request_ ] error:&ns_error])
return;
DLOG(ERROR) << base::SysNSStringToUTF8(
[ns_error localizedDescription]);
});
return true;
}
private:
VisionAPIAsyncRequestMac(Callback callback, Class request_class)
: callback_(std::move(callback)) {
DCHECK(callback_);
scoped_refptr<base::SequencedTaskRunner> task_runner =
base::SequencedTaskRunnerHandle::Get();
const auto handler = ^(VNRequest* request, NSError* error) {
task_runner->PostTask(FROM_HERE,
base::BindOnce(callback_, request, error));
};
request_.reset([[request_class alloc] initWithCompletionHandler:handler]);
}
base::scoped_nsobject<VNRequest> request_;
const Callback callback_;
DISALLOW_COPY_AND_ASSIGN(VisionAPIAsyncRequestMac);
};
FaceDetectionImplMacVision::FaceDetectionImplMacVision() : weak_factory_(this) {
static void* const vision_framework =
dlopen("/System/Library/Frameworks/Vision.framework/Vision", RTLD_LAZY);
if (!vision_framework) {
......@@ -25,15 +106,36 @@ FaceDetectionImplMacVision::FaceDetectionImplMacVision() {
DLOG(ERROR) << "Failed to create VNDetectFaceLandmarksRequest object";
return;
}
landmarks_request_.reset([[request_class alloc] init]);
// The repeating callback will not be run if FaceDetectionImplMacVision object
// has already been destroyed.
landmarks_async_request_ = VisionAPIAsyncRequestMac::Create(
request_class,
base::BindRepeating(&FaceDetectionImplMacVision::OnFacesDetected,
weak_factory_.GetWeakPtr()));
}
FaceDetectionImplMacVision::~FaceDetectionImplMacVision() = default;
void FaceDetectionImplMacVision::Detect(const SkBitmap& bitmap,
DetectCallback callback) {
if (landmarks_request_)
DCHECK(landmarks_async_request_);
if (!landmarks_async_request_->PerformRequest(bitmap)) {
std::move(callback).Run({});
return;
}
// Hold on the callback until async request completes.
detected_callback_ = std::move(callback);
// This prevents the Detect function from being called before the
// VisionAPIAsyncRequestMac completes.
binding_->PauseIncomingMethodCallProcessing();
}
void FaceDetectionImplMacVision::OnFacesDetected(VNRequest* request,
NSError* error) {
std::move(detected_callback_).Run({});
binding_->ResumeIncomingMethodCallProcessing();
}
} // namespace shape_detection
......@@ -32,8 +32,10 @@ void FaceDetectionProviderMac::CreateFaceDetection(
// Vision is more accurate than Core Image Framework, but it also needs more
// processing time.
if (!options->fast_mode) {
mojo::MakeStrongBinding(std::make_unique<FaceDetectionImplMacVision>(),
std::move(request));
auto impl = std::make_unique<FaceDetectionImplMacVision>();
auto* impl_ptr = impl.get();
impl_ptr->SetBinding(
mojo::MakeStrongBinding(std::move(impl), std::move(request)));
return;
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment