blob: 9536be70c50a773a7e34f58d4f21d819cf1eeb3f [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PACKAGES_CAMERA_CAMERA_WINDOWS_WINDOWS_CAPTURE_CONTROLLER_H_
#define PACKAGES_CAMERA_CAMERA_WINDOWS_WINDOWS_CAPTURE_CONTROLLER_H_
#include <d3d11.h>
#include <flutter/texture_registrar.h>
#include <mfapi.h>
#include <mfcaptureengine.h>
#include <mferror.h>
#include <mfidl.h>
#include <windows.h>
#include <wrl/client.h>
#include <memory>
#include <string>
#include "capture_controller_listener.h"
#include "capture_engine_listener.h"
#include "photo_handler.h"
#include "preview_handler.h"
#include "record_handler.h"
#include "texture_handler.h"
namespace camera_windows {
using flutter::TextureRegistrar;
using Microsoft::WRL::ComPtr;
// Camera resolution presets. Used to request a capture resolution.
enum class ResolutionPreset {
// Automatic resolution, uses the highest resolution available.
kAuto,
// 240p (320x240)
kLow,
// 480p (720x480)
kMedium,
// 720p (1280x720)
kHigh,
// 1080p (1920x1080)
kVeryHigh,
// 2160p (4096x2160)
kUltraHigh,
// The highest resolution available.
kMax,
};
// Camera capture engine state.
//
// On creation, |CaptureControllers| start in state |kNotInitialized|.
// On initialization, the capture controller transitions to the |kInitializing|
// and then |kInitialized| state.
enum class CaptureEngineState { kNotInitialized, kInitializing, kInitialized };
// Interface for a class that enumerates video capture device sources.
class VideoCaptureDeviceEnumerator {
private:
virtual bool EnumerateVideoCaptureDeviceSources(IMFActivate*** devices,
UINT32* count) = 0;
};
// Interface implemented by capture controllers.
//
// Capture controllers are used to capture video streams or still photos from
// their associated |Camera|.
class CaptureController {
public:
CaptureController() {}
virtual ~CaptureController() = default;
// Disallow copy and move.
CaptureController(const CaptureController&) = delete;
CaptureController& operator=(const CaptureController&) = delete;
// Initializes the capture controller with the specified device id.
//
// Returns false if the capture controller could not be initialized
// or is already initialized.
//
// texture_registrar: Pointer to Flutter TextureRegistrar instance. Used to
// register texture for capture preview.
// device_id: A string that holds information of camera device id to
// be captured.
// record_audio: A boolean value telling if audio should be captured on
// video recording.
// resolution_preset: Maximum capture resolution height.
virtual bool InitCaptureDevice(TextureRegistrar* texture_registrar,
const std::string& device_id,
bool record_audio,
ResolutionPreset resolution_preset) = 0;
// Returns preview frame width
virtual uint32_t GetPreviewWidth() const = 0;
// Returns preview frame height
virtual uint32_t GetPreviewHeight() const = 0;
// Starts the preview.
virtual void StartPreview() = 0;
// Pauses the preview.
virtual void PausePreview() = 0;
// Resumes the preview.
virtual void ResumePreview() = 0;
// Starts recording video.
virtual void StartRecord(const std::string& file_path,
int64_t max_video_duration_ms) = 0;
// Stops the current video recording.
virtual void StopRecord() = 0;
// Captures a still photo.
virtual void TakePicture(const std::string& file_path) = 0;
};
// Concrete implementation of the |CaptureController| interface.
//
// Handles the video preview stream via a |PreviewHandler| instance, video
// capture via a |RecordHandler| instance, and still photo capture via a
// |PhotoHandler| instance.
class CaptureControllerImpl : public CaptureController,
public CaptureEngineObserver {
public:
static bool EnumerateVideoCaptureDeviceSources(IMFActivate*** devices,
UINT32* count);
explicit CaptureControllerImpl(CaptureControllerListener* listener);
virtual ~CaptureControllerImpl();
// Disallow copy and move.
CaptureControllerImpl(const CaptureControllerImpl&) = delete;
CaptureControllerImpl& operator=(const CaptureControllerImpl&) = delete;
// CaptureController
bool InitCaptureDevice(TextureRegistrar* texture_registrar,
const std::string& device_id, bool record_audio,
ResolutionPreset resolution_preset) override;
uint32_t GetPreviewWidth() const override { return preview_frame_width_; }
uint32_t GetPreviewHeight() const override { return preview_frame_height_; }
void StartPreview() override;
void PausePreview() override;
void ResumePreview() override;
void StartRecord(const std::string& file_path,
int64_t max_video_duration_ms) override;
void StopRecord() override;
void TakePicture(const std::string& file_path) override;
// CaptureEngineObserver
void OnEvent(IMFMediaEvent* event) override;
bool IsReadyForSample() const override {
return capture_engine_state_ == CaptureEngineState::kInitialized &&
preview_handler_ && preview_handler_->IsRunning();
}
bool UpdateBuffer(uint8_t* data, uint32_t data_length) override;
void UpdateCaptureTime(uint64_t capture_time) override;
// Sets capture engine, for testing purposes.
void SetCaptureEngine(IMFCaptureEngine* capture_engine) {
capture_engine_ = capture_engine;
}
// Sets video source, for testing purposes.
void SetVideoSource(IMFMediaSource* video_source) {
video_source_ = video_source;
}
// Sets audio source, for testing purposes.
void SetAudioSource(IMFMediaSource* audio_source) {
audio_source_ = audio_source;
}
private:
// Helper function to return initialized state as boolean;
bool IsInitialized() const {
return capture_engine_state_ == CaptureEngineState::kInitialized;
}
// Resets capture controller state.
// This is called if capture engine creation fails or is disposed.
void ResetCaptureController();
// Returns max preview height calculated from resolution present.
uint32_t GetMaxPreviewHeight() const;
// Uses first audio source to capture audio.
// Note: Enumerating audio sources via platform interface is not supported.
HRESULT CreateDefaultAudioCaptureSource();
// Initializes video capture source from camera device.
HRESULT CreateVideoCaptureSourceForDevice(const std::string& video_device_id);
// Creates DX11 Device and D3D Manager.
HRESULT CreateD3DManagerWithDX11Device();
// Initializes capture engine object.
HRESULT CreateCaptureEngine();
// Enumerates video_sources media types and finds out best resolution
// for preview and video capture.
HRESULT FindBaseMediaTypes();
// Stops timed video record. Called internally when record handler when max
// recording time is exceeded.
void StopTimedRecord();
// Stops preview. Called internally on camera reset and dispose.
HRESULT StopPreview();
// Handles capture engine initalization event.
void OnCaptureEngineInitialized(CameraResult result,
const std::string& error);
// Handles capture engine errors.
void OnCaptureEngineError(CameraResult result, const std::string& error);
// Handles picture events.
void OnPicture(CameraResult result, const std::string& error);
// Handles preview started events.
void OnPreviewStarted(CameraResult result, const std::string& error);
// Handles preview stopped events.
void OnPreviewStopped(CameraResult result, const std::string& error);
// Handles record started events.
void OnRecordStarted(CameraResult result, const std::string& error);
// Handles record stopped events.
void OnRecordStopped(CameraResult result, const std::string& error);
bool media_foundation_started_ = false;
bool record_audio_ = false;
uint32_t preview_frame_width_ = 0;
uint32_t preview_frame_height_ = 0;
UINT dx_device_reset_token_ = 0;
std::unique_ptr<RecordHandler> record_handler_;
std::unique_ptr<PreviewHandler> preview_handler_;
std::unique_ptr<PhotoHandler> photo_handler_;
std::unique_ptr<TextureHandler> texture_handler_;
CaptureControllerListener* capture_controller_listener_;
std::string video_device_id_;
CaptureEngineState capture_engine_state_ =
CaptureEngineState::kNotInitialized;
ResolutionPreset resolution_preset_ = ResolutionPreset::kMedium;
ComPtr<IMFCaptureEngine> capture_engine_;
ComPtr<CaptureEngineListener> capture_engine_callback_handler_;
ComPtr<IMFDXGIDeviceManager> dxgi_device_manager_;
ComPtr<ID3D11Device> dx11_device_;
ComPtr<IMFMediaType> base_capture_media_type_;
ComPtr<IMFMediaType> base_preview_media_type_;
ComPtr<IMFMediaSource> video_source_;
ComPtr<IMFMediaSource> audio_source_;
TextureRegistrar* texture_registrar_ = nullptr;
};
// Inferface for factory classes that create |CaptureController| instances.
class CaptureControllerFactory {
public:
CaptureControllerFactory() {}
virtual ~CaptureControllerFactory() = default;
// Disallow copy and move.
CaptureControllerFactory(const CaptureControllerFactory&) = delete;
CaptureControllerFactory& operator=(const CaptureControllerFactory&) = delete;
// Create and return a |CaptureController| that makes callbacks on the
// specified |CaptureControllerListener|, which must not be null.
virtual std::unique_ptr<CaptureController> CreateCaptureController(
CaptureControllerListener* listener) = 0;
};
// Concreate implementation of |CaptureControllerFactory|.
class CaptureControllerFactoryImpl : public CaptureControllerFactory {
public:
CaptureControllerFactoryImpl() {}
virtual ~CaptureControllerFactoryImpl() = default;
// Disallow copy and move.
CaptureControllerFactoryImpl(const CaptureControllerFactoryImpl&) = delete;
CaptureControllerFactoryImpl& operator=(const CaptureControllerFactoryImpl&) =
delete;
std::unique_ptr<CaptureController> CreateCaptureController(
CaptureControllerListener* listener) override {
return std::make_unique<CaptureControllerImpl>(listener);
}
};
} // namespace camera_windows
#endif // PACKAGES_CAMERA_CAMERA_WINDOWS_WINDOWS_CAPTURE_CONTROLLER_H_