| // 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 |