text: // Copyright (c) 2012 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.
  
  // Windows specific implementation of VideoCaptureDevice.
  // MediaFoundation is used for capturing. MediaFoundation provides its own
  // threads for capturing.
  
  #ifndef MEDIA_CAPTURE_VIDEO_WIN_VIDEO_CAPTURE_DEVICE_MF_WIN_H_
  #define MEDIA_CAPTURE_VIDEO_WIN_VIDEO_CAPTURE_DEVICE_MF_WIN_H_
  
  #include <mfcaptureengine.h>
  #include <mfidl.h>
  #include <mfreadwrite.h>
  #include <stdint.h>
  #include <strmif.h>
  #include <wrl/client.h>
  
  #include <vector>
  
  #include "base/callback_forward.h"
  #include "base/containers/queue.h"
  #include "base/sequence_checker.h"
  #include "media/base/win/dxgi_device_manager.h"
  #include "media/capture/capture_export.h"
  #include "media/capture/video/video_capture_device.h"
  #include "media/capture/video/win/capability_list_win.h"
  #include "media/capture/video/win/metrics.h"
  #include "third_party/abseil-cpp/absl/types/optional.h"
  
  interface IMFSourceReader;
  
  namespace base {
  class Location;
  }  // namespace base
  
  namespace media {
  
  class MFVideoCallback;
  
  class CAPTURE_EXPORT VideoCaptureDeviceMFWin : public VideoCaptureDevice {
   public:
    static bool GetPixelFormatFromMFSourceMediaSubtype(const GUID& guid,
                                                       bool use_hardware_format,
                                                       VideoPixelFormat* format);
    static VideoCaptureControlSupport GetControlSupport(
        Microsoft::WRL::ComPtr<IMFMediaSource> source);
  
    VideoCaptureDeviceMFWin() = delete;
  
    explicit VideoCaptureDeviceMFWin(
        const VideoCaptureDeviceDescriptor& device_descriptor,
        Microsoft::WRL::ComPtr<IMFMediaSource> source,
        scoped_refptr<DXGIDeviceManager> dxgi_device_manager);
    explicit VideoCaptureDeviceMFWin(
        const VideoCaptureDeviceDescriptor& device_descriptor,
        Microsoft::WRL::ComPtr<IMFMediaSource> source,
        scoped_refptr<DXGIDeviceManager> dxgi_device_manager,
        Microsoft::WRL::ComPtr<IMFCaptureEngine> engine);
  
    VideoCaptureDeviceMFWin(const VideoCaptureDeviceMFWin&) = delete;
    VideoCaptureDeviceMFWin& operator=(const VideoCaptureDeviceMFWin&) = delete;
  
    ~VideoCaptureDeviceMFWin() override;
  
    // Opens the device driver for this device.
    bool Init();
  
    // VideoCaptureDevice implementation.
    void AllocateAndStart(
        const VideoCaptureParams& params,
        std::unique_ptr<VideoCaptureDevice::Client> client) override;
    void StopAndDeAllocate() override;
    void TakePhoto(TakePhotoCallback callback) override;
    void GetPhotoState(GetPhotoStateCallback callback) override;
    void SetPhotoOptions(mojom::PhotoSettingsPtr settings,
                         SetPhotoOptionsCallback callback) override;
    void OnUtilizationReport(int frame_feedback_id,
                             media::VideoCaptureFeedback feedback) override;
  
    // Captured new video data.
    void OnIncomingCapturedData(IMFMediaBuffer* buffer,
                                base::TimeTicks reference_time,
                                base::TimeDelta timestamp);
    void OnFrameDropped(VideoCaptureFrameDropReason reason);
    void OnEvent(IMFMediaEvent* media_event);
  
    using CreateMFPhotoCallbackCB =
        base::RepeatingCallback<scoped_refptr<IMFCaptureEngineOnSampleCallback>(
            VideoCaptureDevice::TakePhotoCallback callback,
            VideoCaptureFormat format)>;
  
    bool get_use_photo_stream_to_take_photo_for_testing() {
      return !photo_capabilities_.empty();
    }
  
    void set_create_mf_photo_callback_for_testing(CreateMFPhotoCallbackCB cb) {
      create_mf_photo_callback_ = cb;
    }
  
    void set_max_retry_count_for_testing(int max_retry_count) {
      max_retry_count_ = max_retry_count;
    }
  
    void set_retry_delay_in_ms_for_testing(int retry_delay_in_ms) {
      retry_delay_in_ms_ = retry_delay_in_ms;
    }
  
    void set_dxgi_device_manager_for_testing(
        scoped_refptr<DXGIDeviceManager> dxgi_device_manager) {
      dxgi_device_manager_ = std::move(dxgi_device_manager);
    }
  
    absl::optional<int> camera_rotation() const { return camera_rotation_; }
  
   private:
    HRESULT ExecuteHresultCallbackWithRetries(
        base::RepeatingCallback<HRESULT()> callback,
        MediaFoundationFunctionRequiringRetry which_function);
    HRESULT GetDeviceStreamCount(IMFCaptureSource* source, DWORD* count);
    HRESULT GetDeviceStreamCategory(
        IMFCaptureSource* source,
        DWORD stream_index,
        MF_CAPTURE_ENGINE_STREAM_CATEGORY* stream_category);
    HRESULT GetAvailableDeviceMediaType(IMFCaptureSource* source,
                                        DWORD stream_index,
                                        DWORD media_type_index,
                                        IMFMediaType** type);
  
    HRESULT FillCapabilities(IMFCaptureSource* source,
                             bool photo,
                             CapabilityList* capabilities);
    void OnError(VideoCaptureError error,
                 const base::Location& from_here,
                 HRESULT hr);
    void OnError(VideoCaptureError error,
                 const base::Location& from_here,
                 const char* message);
    void SendOnStartedIfNotYetSent();
    HRESULT WaitOnCaptureEvent(GUID capture_event_guid);
    HRESULT DeliverTextureToClient(ID3D11Texture2D* texture,
                                   base::TimeTicks reference_time,
                                   base::TimeDelta timestamp)
        EXCLUSIVE_LOCKS_REQUIRED(lock_);
    void OnIncomingCapturedDataInternal(
        IMFMediaBuffer* buffer,
        base::TimeTicks reference_time,
        base::TimeDelta timestamp,
        VideoCaptureFrameDropReason& frame_drop_reason);
    bool RecreateMFSource();
    void AllocateAndStartLocked(
        const VideoCaptureParams& params,
        std::unique_ptr<VideoCaptureDevice::Client> client);
  
    VideoCaptureDeviceDescriptor device_descriptor_;
    CreateMFPhotoCallbackCB create_mf_photo_callback_;
    scoped_refptr<MFVideoCallback> video_callback_;
    bool is_initialized_;
    int max_retry_count_;
    int retry_delay_in_ms_;
  
    // Guards the below variables from concurrent access between methods running
    // on |sequence_checker_| and calls to OnIncomingCapturedData() and OnEvent()
    // made by MediaFoundation on threads outside of our control.
    base::Lock lock_;
  
    std::unique_ptr<VideoCaptureDevice::Client> client_;
    Microsoft::WRL::ComPtr<IMFMediaSource> source_;
    Microsoft::WRL::ComPtr<IAMCameraControl> camera_control_;
    Microsoft::WRL::ComPtr<IAMVideoProcAmp> video_control_;
    Microsoft::WRL::ComPtr<IMFCaptureEngine> engine_;
    std::unique_ptr<CapabilityWin> selected_video_capability_;
    CapabilityList photo_capabilities_;
    std::unique_ptr<CapabilityWin> selected_photo_capability_;
    bool is_started_;
    bool has_sent_on_started_to_client_;
    // These flags keep the manual/auto mode between cycles of SetPhotoOptions().
    bool exposure_mode_manual_;
    bool focus_mode_manual_;
    bool white_balance_mode_manual_;
    base::queue<TakePhotoCallback> video_stream_take_photo_callbacks_;
    base::WaitableEvent capture_initialize_;
    base::WaitableEvent capture_error_;
    scoped_refptr<DXGIDeviceManager> dxgi_device_manager_;
    absl::optional<int> camera_rotation_;
    VideoCaptureParams params_;
    int num_restarts_ = 0;
  
    media::VideoCaptureFeedback last_feedback_;
  
    SEQUENCE_CHECKER(sequence_checker_);
  };
  
  }  // namespace media
  
  #endif  // MEDIA_CAPTURE_VIDEO_WIN_VIDEO_CAPTURE_DEVICE_MF_WIN_H_
  