| // 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/strong_binding.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( |
| shape_detection::mojom::FaceDetectionRequest request, |
| 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(request), |
| 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. |
| binding_->PauseIncomingMethodCallProcessing(); |
| } |
| |
| FaceDetectionProviderWin::FaceDetectionProviderWin() : weak_factory_(this) {} |
| |
| FaceDetectionProviderWin::~FaceDetectionProviderWin() = default; |
| |
| void FaceDetectionProviderWin::OnFaceDetectorCreated( |
| shape_detection::mojom::FaceDetectionRequest request, |
| BitmapPixelFormat pixel_format, |
| ComPtr<IFaceDetector> face_detector) { |
| binding_->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->SetBinding( |
| mojo::MakeStrongBinding(std::move(impl), std::move(request))); |
| } |
| |
| } // namespace shape_detection |