blob: 341884e6c8eee477fb39fb6345c8f377453a3bd1 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/shape_detection/face_detection_provider_win.h"
#include <windows.media.faceanalysis.h>
#include "base/bind.h"
#include "base/logging.h"
#include "base/scoped_generic.h"
#include "base/win/core_winrt_util.h"
#include "base/win/post_async_results.h"
#include "base/win/scoped_hstring.h"
#include "base/win/windows_version.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace shape_detection {
namespace {
using ABI::Windows::Foundation::IAsyncOperation;
using ABI::Windows::Graphics::Imaging::BitmapPixelFormat;
using ABI::Windows::Graphics::Imaging::ISoftwareBitmapStatics;
using ABI::Windows::Media::FaceAnalysis::FaceDetector;
using ABI::Windows::Media::FaceAnalysis::IFaceDetector;
using ABI::Windows::Media::FaceAnalysis::IFaceDetectorStatics;
using base::win::GetActivationFactory;
using base::win::ScopedHString;
using Microsoft::WRL::ComPtr;
BitmapPixelFormat GetPreferredPixelFormat(IFaceDetectorStatics* factory) {
static constexpr BitmapPixelFormat kFormats[] = {
ABI::Windows::Graphics::Imaging::BitmapPixelFormat_Gray8,
ABI::Windows::Graphics::Imaging::BitmapPixelFormat_Nv12};
for (const auto& format : kFormats) {
boolean is_supported = false;
factory->IsBitmapPixelFormatSupported(format, &is_supported);
if (is_supported)
return format;
}
return ABI::Windows::Graphics::Imaging::BitmapPixelFormat_Unknown;
}
} // namespace
void FaceDetectionProviderWin::CreateFaceDetection(
mojo::PendingReceiver<shape_detection::mojom::FaceDetection> receiver,
shape_detection::mojom::FaceDetectorOptionsPtr options) {
// FaceDetector class is only available in Win 10 onwards (v10.0.10240.0).
if (base::win::GetVersion() < base::win::Version::WIN10) {
DVLOG(1) << "FaceDetector not supported before Windows 10";
return;
}
// Loads functions dynamically at runtime to prevent library dependencies.
if (!(base::win::ResolveCoreWinRTDelayload() &&
ScopedHString::ResolveCoreWinRTStringDelayload())) {
DLOG(ERROR) << "Failed loading functions from combase.dll";
return;
}
ComPtr<IFaceDetectorStatics> factory;
HRESULT hr = GetActivationFactory<
IFaceDetectorStatics,
RuntimeClass_Windows_Media_FaceAnalysis_FaceDetector>(&factory);
if (FAILED(hr)) {
DLOG(ERROR) << "IFaceDetectorStatics factory failed: "
<< logging::SystemErrorCodeToString(hr);
return;
}
boolean is_supported = false;
factory->get_IsSupported(&is_supported);
if (!is_supported)
return;
// In the current version, the FaceDetector class only supports images in
// Gray8 or Nv12. Gray8 should be a good type but verify it against
// FaceDetector’s supported formats.
BitmapPixelFormat pixel_format = GetPreferredPixelFormat(factory.Get());
if (pixel_format ==
ABI::Windows::Graphics::Imaging::BitmapPixelFormat_Unknown) {
return;
}
// Create an instance of FaceDetector asynchronously.
ComPtr<IAsyncOperation<FaceDetector*>> async_op;
hr = factory->CreateAsync(&async_op);
if (FAILED(hr)) {
DLOG(ERROR) << "Create FaceDetector failed: "
<< logging::SystemErrorCodeToString(hr);
return;
}
// Use WeakPtr to bind the callback so that the once callback will not be run
// if this object has been already destroyed.
hr = base::win::PostAsyncResults(
std::move(async_op),
base::BindOnce(&FaceDetectionProviderWin::OnFaceDetectorCreated,
weak_factory_.GetWeakPtr(), std::move(receiver),
pixel_format));
if (FAILED(hr)) {
DLOG(ERROR) << "Begin async operation failed: "
<< logging::SystemErrorCodeToString(hr);
return;
}
// When |provider| goes out of scope it will immediately close its end of
// the message pipe, then the callback OnFaceDetectorCreated will be not
// called. This prevents this object from being destroyed before the
// AsyncOperation completes.
receiver_->PauseIncomingMethodCallProcessing();
}
FaceDetectionProviderWin::FaceDetectionProviderWin() {}
FaceDetectionProviderWin::~FaceDetectionProviderWin() = default;
void FaceDetectionProviderWin::OnFaceDetectorCreated(
mojo::PendingReceiver<shape_detection::mojom::FaceDetection> receiver,
BitmapPixelFormat pixel_format,
ComPtr<IFaceDetector> face_detector) {
receiver_->ResumeIncomingMethodCallProcessing();
if (!face_detector)
return;
ComPtr<ISoftwareBitmapStatics> bitmap_factory;
const HRESULT hr = GetActivationFactory<
ISoftwareBitmapStatics,
RuntimeClass_Windows_Graphics_Imaging_SoftwareBitmap>(&bitmap_factory);
if (FAILED(hr)) {
DLOG(ERROR) << "ISoftwareBitmapStatics factory failed: "
<< logging::SystemErrorCodeToString(hr);
return;
}
auto impl = std::make_unique<FaceDetectionImplWin>(
std::move(face_detector), std::move(bitmap_factory), pixel_format);
auto* impl_ptr = impl.get();
impl_ptr->SetReceiver(
mojo::MakeSelfOwnedReceiver(std::move(impl), std::move(receiver)));
}
} // namespace shape_detection